From 8b7caedbec33bc442b98764ba981903a8da97993 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 2 Jun 2015 10:45:50 -0700 Subject: [PATCH 01/40] Remove EmitResolver.getExpressionNameSubstitution Add EmitResolver.getReferencedExportContainer Add EmitResolver.getReferencedImportDeclaration Clean up getGeneratedNameForNode in emitter.ts Switch isNotExpressionIdentifier to isExpressionIdentifier in emitter.ts Revise emitExpressionIdentifier in emitter.ts --- src/compiler/checker.ts | 110 ++++++++------------ src/compiler/emitter.ts | 216 +++++++++++++++++++++------------------- src/compiler/types.ts | 3 +- 3 files changed, 155 insertions(+), 174 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 759b235ad0a..6257031afbd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11784,76 +11784,39 @@ module ts { // Emitter support - function isExternalModuleSymbol(symbol: Symbol): boolean { - return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile; - } - - function getAliasNameSubstitution(symbol: Symbol, getGeneratedNameForNode: (node: Node) => string): string { - // If this is es6 or higher, just use the name of the export - // no need to qualify it. - if (languageVersion >= ScriptTarget.ES6) { - return undefined; - } - - let node = getDeclarationOfAliasSymbol(symbol); - if (node) { - if (node.kind === SyntaxKind.ImportClause) { - let defaultKeyword: string; - - if (languageVersion === ScriptTarget.ES3) { - defaultKeyword = "[\"default\"]"; - } else { - defaultKeyword = ".default"; - } - return getGeneratedNameForNode(node.parent) + defaultKeyword; - } - if (node.kind === SyntaxKind.ImportSpecifier) { - let moduleName = getGeneratedNameForNode(node.parent.parent.parent); - let propertyName = (node).propertyName || (node).name; - return moduleName + "." + unescapeIdentifier(propertyName.text); - } - } - } - - function getExportNameSubstitution(symbol: Symbol, location: Node, getGeneratedNameForNode: (Node: Node) => string): string { - if (isExternalModuleSymbol(symbol.parent)) { - // 1. If this is es6 or higher, just use the name of the export - // no need to qualify it. - // 2. export mechanism for System modules is different from CJS\AMD - // and it does not need qualifications for exports - if (languageVersion >= ScriptTarget.ES6 || compilerOptions.module === ModuleKind.System) { - return undefined; - } - return "exports." + unescapeIdentifier(symbol.name); - } - let node = location; - let containerSymbol = getParentOfSymbol(symbol); - while (node) { - if ((node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(node) === containerSymbol) { - return getGeneratedNameForNode(node) + "." + unescapeIdentifier(symbol.name); - } - node = node.parent; - } - } - - function getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (Node: Node) => string): string { - let symbol = getNodeLinks(node).resolvedSymbol || (isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); + // When resolved as an expression identifier, if the given node references an exported entity, return the declaration + // node of the exported entity's container. Otherwise, return undefined. + function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration { + let symbol = getReferencedValueSymbol(node); if (symbol) { - // Whan an identifier resolves to a parented symbol, it references an exported entity from - // another declaration of the same internal module. - if (symbol.parent) { - return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode); + if (symbol.flags & SymbolFlags.ExportValue) { + let exportSymbol = getMergedSymbol(symbol.exportSymbol); + if (!(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { + symbol = exportSymbol; + } } - // If we reference an exported entity within the same module declaration, then whether - // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the - // kinds that we do NOT prefix. - let exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - if (symbol !== exportSymbol && !(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { - return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode); + let parentSymbol = getParentOfSymbol(symbol); + if (parentSymbol) { + if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration.kind === SyntaxKind.SourceFile) { + return parentSymbol.valueDeclaration; + } + for (let n = node.parent; n; n = n.parent) { + if ((n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.EnumDeclaration) && getSymbolOfNode(n) === parentSymbol) { + return n; + } + } } - // Named imports from ES6 import declarations are rewritten - if (symbol.flags & SymbolFlags.Alias) { - return getAliasNameSubstitution(symbol, getGeneratedNameForNode); + } + } + + // When resolved as an expression identifier, if the given node references a default import or a named import, return + // the declaration node of that import. Otherwise, return undefined. + function getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier { + let symbol = getReferencedValueSymbol(node); + if (symbol && symbol.flags & SymbolFlags.Alias) { + let declaration = getDeclarationOfAliasSymbol(symbol); + if (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier) { + return declaration; } } } @@ -12182,12 +12145,15 @@ module ts { return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); } + function getReferencedValueSymbol(reference: Identifier): Symbol { + return getNodeLinks(reference).resolvedSymbol || + resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + function getReferencedValueDeclaration(reference: Identifier): Declaration { Debug.assert(!nodeIsSynthesized(reference)); - let symbol = - getNodeLinks(reference).resolvedSymbol || - resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.Alias, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - + let symbol = getReferencedValueSymbol(reference); return symbol && getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration; } @@ -12233,6 +12199,8 @@ module ts { function createResolver(): EmitResolver { return { getExpressionNameSubstitution, + getReferencedExportContainer, + getReferencedImportDeclaration, isValueAliasDeclaration, hasGlobalName, isReferencedAliasDeclaration, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 32ebeaec08f..2414c88a7a9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -249,81 +249,42 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function assignGeneratedName(node: Node, name: string) { - nodeToGeneratedName[getNodeId(node)] = unescapeIdentifier(name); - } - - function generateNameForFunctionOrClassDeclaration(node: Declaration) { - if (!node.name) { - assignGeneratedName(node, makeUniqueName("default")); - } - } - function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { - if (node.name.kind === SyntaxKind.Identifier) { - let name = node.name.text; - // Use module/enum name itself if it is unique, otherwise make a unique variation - assignGeneratedName(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name)); - } + let name = node.name.text; + // Use module/enum name itself if it is unique, otherwise make a unique variation + return isUniqueLocalName(name, node) ? name : makeUniqueName(name); } function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { let expr = getExternalModuleName(node); let baseName = expr.kind === SyntaxKind.StringLiteral ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; - assignGeneratedName(node, makeUniqueName(baseName)); + return makeUniqueName(baseName); } - function generateNameForImportDeclaration(node: ImportDeclaration) { - if (node.importClause) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportDeclaration(node: ExportDeclaration) { - if (node.moduleSpecifier) { - generateNameForImportOrExportDeclaration(node); - } - } - - function generateNameForExportAssignment(node: ExportAssignment) { - if (node.expression && node.expression.kind !== SyntaxKind.Identifier) { - assignGeneratedName(node, makeUniqueName("default")); - } + function generateNameForExportDefault() { + return makeUniqueName("default"); } function generateNameForNode(node: Node) { switch (node.kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return generateNameForModuleOrEnum(node); + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: + return generateNameForImportOrExportDeclaration(node); case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - generateNameForFunctionOrClassDeclaration(node); - break; - case SyntaxKind.ModuleDeclaration: - generateNameForModuleOrEnum(node); - generateNameForNode((node).body); - break; - case SyntaxKind.EnumDeclaration: - generateNameForModuleOrEnum(node); - break; - case SyntaxKind.ImportDeclaration: - generateNameForImportDeclaration(node); - break; - case SyntaxKind.ExportDeclaration: - generateNameForExportDeclaration(node); - break; case SyntaxKind.ExportAssignment: - generateNameForExportAssignment(node); - break; + return generateNameForExportDefault(); } } function getGeneratedNameForNode(node: Node) { - let nodeId = getNodeId(node); - if (!nodeToGeneratedName[nodeId]) { - generateNameForNode(node); - } - return nodeToGeneratedName[nodeId]; + let id = getNodeId(node); + return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateNameForNode(node))); } function initializeEmitterWithSourceMaps() { @@ -1201,51 +1162,96 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function isNotExpressionIdentifier(node: Identifier) { + function isExpressionIdentifier(node: Node): boolean { let parent = node.parent; switch (parent.kind) { - case SyntaxKind.Parameter: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.BindingElement: - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ImportClause: - case SyntaxKind.NamespaceImport: - return (parent).name === node; - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - return (parent).name === node || (parent).propertyName === node; - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.CaseClause: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.Decorator: + case SyntaxKind.DeleteExpression: + case SyntaxKind.DoStatement: + case SyntaxKind.ElementAccessExpression: case SyntaxKind.ExportAssignment: - return false; - case SyntaxKind.LabeledStatement: - return (node.parent).label === node; + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.NewExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SwitchStatement: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TemplateSpan: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.YieldExpression: + return true; + case SyntaxKind.BindingElement: + case SyntaxKind.EnumMember: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).initializer === node; + case SyntaxKind.PropertyAccessExpression: + return (parent).expression === node; + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + return (parent).body === node; + case SyntaxKind.ImportEqualsDeclaration: + return (parent).moduleReference === node; + case SyntaxKind.QualifiedName: + return (parent).left === node; } + return false; } function emitExpressionIdentifier(node: Identifier) { - let substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode); - if (substitution) { - write(substitution); + let container = resolver.getReferencedExportContainer(node); + if (container) { + if (container.kind === SyntaxKind.SourceFile) { + // Identifier references module export + if (languageVersion < ScriptTarget.ES6 && compilerOptions.module !== ModuleKind.System) { + write("exports."); + } + } + else { + // Identifier references namespace export + write(getGeneratedNameForNode(container)); + write("."); + } } - else { - writeTextOfNode(currentSourceFile, node); + else if (languageVersion < ScriptTarget.ES6) { + let declaration = resolver.getReferencedImportDeclaration(node); + if (declaration) { + if (declaration.kind === SyntaxKind.ImportClause) { + // Identifier references default import + write(getGeneratedNameForNode(declaration.parent)); + write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); + } + else { + // Identifier references named import + write(getGeneratedNameForNode(declaration.parent.parent.parent)); + write("."); + writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + } + return; + } } + writeTextOfNode(currentSourceFile, node); } function getGeneratedNameForIdentifier(node: Identifier): string { @@ -1272,7 +1278,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { if (!node.parent) { write(node.text); } - else if (!isNotExpressionIdentifier(node)) { + else if (isExpressionIdentifier(node)) { emitExpressionIdentifier(node); } else { @@ -1709,12 +1715,15 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitExpressionIdentifier(node.name); } } - else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) { - // Emit identifier as an identifier - write(": "); - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); + else { + let container = resolver.getReferencedExportContainer(node.name); + if (container && container.kind !== SyntaxKind.SourceFile) { + // Emit identifier as an identifier + write(": "); + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } + emitExpressionIdentifier(node.name); + } } } @@ -4983,13 +4992,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } - function getLocalNameForExternalImport(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { - let namespaceDeclaration = getNamespaceDeclarationNode(importNode); - if (namespaceDeclaration && !isDefaultImport(importNode)) { + function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + let namespaceDeclaration = getNamespaceDeclarationNode(node); + if (namespaceDeclaration && !isDefaultImport(node)) { return getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name); } - else { - return getGeneratedNameForNode(importNode); + if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { + return getGeneratedNameForNode(node); + } + if (node.kind === SyntaxKind.ExportDeclaration && (node).moduleSpecifier) { + return getGeneratedNameForNode(node); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 14e53ee8f72..e64d6afad8e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1396,7 +1396,8 @@ module ts { /* @internal */ export interface EmitResolver { hasGlobalName(name: string): boolean; - getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (node: Node) => string): string; + getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; + getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; From 9515947092941127079a06a8d3d6bac245898835 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:07 +0800 Subject: [PATCH 02/40] Adds custom type guard --- src/compiler/checker.ts | 162 ++++++++++++++++-- .../diagnosticInformationMap.generated.ts | 5 + src/compiler/diagnosticMessages.json | 21 +++ src/compiler/parser.ts | 20 ++- src/compiler/scanner.ts | 1 + src/compiler/types.ts | 19 +- 6 files changed, 210 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fad7293412e..a09a2736aac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -97,8 +97,8 @@ module ts { let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false); - let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false); + let anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, false, false); + let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, false, false); let globals: SymbolTable = {}; @@ -2772,7 +2772,7 @@ module ts { function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { if (!(type).declaredProperties) { - var symbol = type.symbol; + let symbol = type.symbol; (type).declaredProperties = getNamedMembers(symbol.members); (type).declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]); (type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]); @@ -2782,7 +2782,7 @@ module ts { return type; } - function resolveClassOrInterfaceMembers(type: InterfaceType): void { + function resolveClassOrInterfaceMembers(type: InterfaceType) { let target = resolveDeclaredMembers(type); let members = target.symbol.members; let callSignatures = target.declaredCallSignatures; @@ -2823,12 +2823,13 @@ module ts { } function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], - resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { + resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { let sig = new Signature(checker); sig.declaration = declaration; sig.typeParameters = typeParameters; sig.parameters = parameters; sig.resolvedReturnType = resolvedReturnType; + sig.typePredicate = typePredicate; sig.minArgumentCount = minArgumentCount; sig.hasRestParameter = hasRestParameter; sig.hasStringLiterals = hasStringLiterals; @@ -2836,7 +2837,7 @@ module ts { } function cloneSignature(sig: Signature): Signature { - return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, + return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); } @@ -2853,7 +2854,7 @@ module ts { return signature; }); } - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, false, false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)]; } function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable { @@ -3229,7 +3230,24 @@ module ts { } let returnType: Type; - if (classType) { + let typePredicate: TypePredicate; + if (declaration.typePredicate) { + returnType = booleanType; + let typePredicateNode = declaration.typePredicate; + let links = getNodeLinks(typePredicateNode); + if (links.typePredicateParameterIndex === undefined) { + links.typePredicateParameterIndex = getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName); + } + if (!links.typeFromTypePredicate) { + links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type); + } + typePredicate = { + parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, + parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, + type: links.typeFromTypePredicate + }; + } + else if (classType) { returnType = classType; } else if (declaration.type) { @@ -3248,8 +3266,8 @@ module ts { } } - links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, - minArgumentCount, hasRestParameter(declaration), hasStringLiterals); + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, + minArgumentCount, hasRestParameters(declaration), hasStringLiterals); } return links.resolvedSignature; } @@ -3962,9 +3980,13 @@ module ts { freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); } + if (signature.typePredicate) { + signature.typePredicate.type = instantiateType(signature.typePredicate.type, mapper); + } let result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, + signature.typePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); result.target = signature; result.mapper = mapper; @@ -4632,6 +4654,43 @@ module ts { } result &= related; } + + if (source.typePredicate && target.typePredicate) { + if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex || + source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + + if (reportErrors) { + let sourceParamText = source.typePredicate.parameterName; + let targetParamText = target.typePredicate.parameterName; + let sourceTypeText = typeToString(source.typePredicate.type); + let targetTypeText = typeToString(target.typePredicate.type); + + if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex) { + reportError(Diagnostics.Parameter_index_from_0_does_not_match_the_parameter_index_from_1, + sourceParamText, + targetParamText); + } + if (source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, + sourceTypeText, + targetTypeText); + } + + reportError(Diagnostics.Type_guard_annotation_0_is_not_assignable_to_1, + `${sourceParamText} is ${sourceTypeText}`, + `${targetParamText} is ${targetTypeText}`); + } + + return Ternary.False; + } + } + else if (!source.typePredicate && target.typePredicate) { + if (reportErrors) { + reportError(Diagnostics.A_non_type_guard_function_is_not_assignable_to_a_type_guard_function); + } + return Ternary.False; + } + let t = getReturnTypeOfSignature(target); if (t === voidType) return result; let s = getReturnTypeOfSignature(source); @@ -5164,6 +5223,13 @@ module ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromTypes); + if (source.typePredicate && + target.typePredicate && + target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { + + inferFromTypes(source.typePredicate.type, target.typePredicate.type); + return; + } inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } @@ -5545,7 +5611,7 @@ module ts { let targetType: Type; let prototypeProperty = getPropertyOfType(rightType, "prototype"); if (prototypeProperty) { - // Target type is type of the protoype property + // Target type is type of the prototype property let prototypePropertyType = getTypeOfSymbol(prototypeProperty); if (prototypePropertyType !== anyType) { targetType = prototypePropertyType; @@ -5561,7 +5627,6 @@ module ts { else if (rightType.flags & TypeFlags.Anonymous) { constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct); } - if (constructSignatures && constructSignatures.length) { targetType = getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))); } @@ -5581,10 +5646,38 @@ module ts { return type; } + function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { + if (type.flags & TypeFlags.Any) { + return type; + } + let signature = getResolvedSignature(expr); + if (!assumeTrue) { + if (type.flags & TypeFlags.Union && signature.typePredicate) { + return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); + } + return type; + } + if (signature.typePredicate) { + if (expr.arguments && expr.arguments[signature.typePredicate.parameterIndex]) { + if (getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + if (isTypeSubtypeOf(signature.typePredicate.type, type)) { + return signature.typePredicate.type; + } + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); + } + } + } + } + return type; + } + // Narrow the given type based on the given expression having the assumed boolean value. The returned type // will be a subtype or the same type as the argument. function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { switch (expr.kind) { + case SyntaxKind.CallExpression: + return narrowTypeByTypePredicate(type, expr, assumeTrue); case SyntaxKind.ParenthesizedExpression: return narrowType(type, (expr).expression, assumeTrue); case SyntaxKind.BinaryExpression: @@ -8486,6 +8579,20 @@ module ts { node.kind === SyntaxKind.FunctionExpression; } + function getTypePredicateParameterIndex(parameterList: NodeArray, parameter: Identifier): number { + let index = -1; + if (parameterList) { + for (let i = 0; i < parameterList.length; i++) { + let param = parameterList[i]; + if (param.name.kind === SyntaxKind.Identifier && + (param.name).text === parameter.text) { + + return i; + } + } + } + } + function checkSignatureDeclaration(node: SignatureDeclaration) { // Grammar checking if (node.kind === SyntaxKind.IndexSignature) { @@ -8506,6 +8613,27 @@ module ts { checkSourceElement(node.type); } + if (node.typePredicate) { + let links = getNodeLinks(node.typePredicate); + if (links.typePredicateParameterIndex === undefined) { + links.typePredicateParameterIndex = getTypePredicateParameterIndex(node.parameters, node.typePredicate.parameterName); + } + if (!links.typeFromTypePredicate) { + links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type); + } + if (links.typePredicateParameterIndex >= 0) { + checkTypeAssignableTo( + links.typeFromTypePredicate, + getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), + node.typePredicate.type); + } + else if(node.typePredicate.parameterName) { + error(node.typePredicate.parameterName, + Diagnostics.Cannot_find_parameter_0, + node.typePredicate.parameterName.text); + } + } + if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); if (compilerOptions.noImplicitAny && !node.type) { @@ -10065,9 +10193,6 @@ module ts { if (node.expression) { let func = getContainingFunction(node); if (func) { - let returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); - let exprType = checkExpressionCached(node.expression); - if (func.asteriskToken) { // A generator does not need its return expressions checked against its return type. // Instead, the yield expressions are checked against the element type. @@ -10076,6 +10201,13 @@ module ts { return; } + let signature = getSignatureFromDeclaration(func); + let exprType = checkExpressionCached(node.expression); + if (signature.typePredicate && exprType !== booleanType) { + error(node.expression, Diagnostics.A_type_guard_function_can_only_return_a_boolean); + } + let returnType = getReturnTypeOfSignature(signature); + if (func.kind === SyntaxKind.SetAccessor) { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 8ccc9d890e2..5a87f67ddd3 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -179,6 +179,11 @@ module ts { Generators_are_not_allowed_in_an_ambient_context: { code: 1221, category: DiagnosticCategory.Error, key: "Generators are not allowed in an ambient context." }, An_overload_signature_cannot_be_declared_as_a_generator: { code: 1222, category: DiagnosticCategory.Error, key: "An overload signature cannot be declared as a generator." }, _0_tag_already_specified: { code: 1223, category: DiagnosticCategory.Error, key: "'{0}' tag already specified." }, + A_non_type_guard_function_is_not_assignable_to_a_type_guard_function: { code: 1224, category: DiagnosticCategory.Error, key: "A non-type guard function is not assignable to a type guard function." }, + A_type_guard_function_can_only_return_a_boolean: { code: 1225, category: DiagnosticCategory.Error, key: "A type-guard function can only return a boolean." }, + Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, + Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, + Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index fb246955f73..0053b071438 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -703,6 +703,27 @@ "category": "Error", "code": 1223 }, + "A non-type guard function is not assignable to a type guard function.": { + "category": "Error", + "code": 1224 + }, + "A type-guard function can only return a boolean.": { + "category": "Error", + "code": 1225 + }, + "Cannot find parameter '{0}'.": { + "category": "Error", + "code": 1226 + }, + "Type-guard annotation '{0}' is not assignable to '{1}'.": { + "category": "Error", + "code": 1227 + }, + "Parameter index from '{0}' does not match the parameter index from '{1}'.": { + "category": "Error", + "code": 1228 + }, + "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 80c70a250fb..ac4517a0b79 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -81,7 +81,8 @@ module ts { visitNodes(cbNodes, node.modifiers) || visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || - visitNode(cbNode, (node).type); + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).typePredicate); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: @@ -98,11 +99,15 @@ module ts { visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).typePredicate) || visitNode(cbNode, (node).equalsGreaterThanToken) || visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: return visitNode(cbNode, (node).typeName) || visitNodes(cbNodes, (node).typeArguments); + case SyntaxKind.TypePredicate: + return visitNode(cbNode, (node).parameterName) || + visitNode(cbNode, (node).type); case SyntaxKind.TypeQuery: return visitNode(cbNode, (node).exprName); case SyntaxKind.TypeLiteral: @@ -763,7 +768,7 @@ module ts { return (contextFlags & ParserContextFlags.Decorator) !== 0; } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { + function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any) { let start = scanner.getTokenPos(); let length = scanner.getTextPos() - start; @@ -2025,6 +2030,17 @@ module ts { else if (parseOptional(returnToken)) { signature.type = parseType(); } + if (token === SyntaxKind.IsKeyword) { + let node = createNode(SyntaxKind.TypePredicate); + node.pos = signature.type.pos; + node.parameterName = (signature.type).typeName; + + nextToken(); + + node.type = parseType(); + signature.type = undefined; + signature.typePredicate = finishNode(node); + } } // Note: after careful analysis of the grammar, it does not appear to be possible to diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 89ac837ab24..d7e65dff81c 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -72,6 +72,7 @@ module ts { "in": SyntaxKind.InKeyword, "instanceof": SyntaxKind.InstanceOfKeyword, "interface": SyntaxKind.InterfaceKeyword, + "is": SyntaxKind.IsKeyword, "let": SyntaxKind.LetKeyword, "module": SyntaxKind.ModuleKeyword, "namespace": SyntaxKind.NamespaceKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0fcf0e1f67a..acf71db16c7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -137,6 +137,7 @@ module ts { ConstructorKeyword, DeclareKeyword, GetKeyword, + IsKeyword, ModuleKeyword, NamespaceKeyword, RequireKeyword, @@ -169,6 +170,7 @@ module ts { ConstructSignature, IndexSignature, // Type + TypePredicate, TypeReference, FunctionType, ConstructorType, @@ -462,6 +464,7 @@ module ts { typeParameters?: NodeArray; parameters: NodeArray; type?: TypeNode; + typePredicate?: TypePredicateNode; } // SyntaxKind.VariableDeclaration @@ -605,6 +608,11 @@ module ts { typeName: EntityName; typeArguments?: NodeArray; } + + export interface TypePredicateNode extends TypeNode { + parameterName?: Identifier; + type: TypeNode; + } export interface TypeQueryNode extends TypeNode { exprName: EntityName; @@ -1376,6 +1384,12 @@ module ts { NotAccessible, CannotBeNamed } + + export interface TypePredicate { + parameterName: string; + parameterIndex?: number; + type: Type; + } /* @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -1563,6 +1577,8 @@ module ts { assignmentChecks?: Map; // Cache of assignment checks hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context importOnRightSide?: Symbol; // for import declarations - import that appear on the right side + typePredicateParameterIndex?: number; // Index of type predicate parameter + typeFromTypePredicate?: Type; // Type from TypePredicate } export const enum TypeFlags { @@ -1588,7 +1604,7 @@ module ts { /* @internal */ ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type /* @internal */ - ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type + ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type ESSymbol = 0x00100000, // Type of symbol primitive introduced in ES6 /* @internal */ @@ -1703,6 +1719,7 @@ module ts { declaration: SignatureDeclaration; // Originating declaration typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) parameters: Symbol[]; // Parameters + typePredicate?: TypePredicate; // Type predicate /* @internal */ resolvedReturnType: Type; // Resolved return type /* @internal */ From 284b9db268ebc85445e3e2131e98ce68f7e6e4dc Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:23 +0800 Subject: [PATCH 03/40] Fixes old tests --- tests/baselines/reference/APISample_linter.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index cd2df23ffbf..9b2675535f2 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 187 /* ForStatement */: - case 188 /* ForInStatement */: - case 186 /* WhileStatement */: - case 185 /* DoStatement */: - if (node.statement.kind !== 180 /* Block */) { + case 189 /* ForStatement */: + case 190 /* ForInStatement */: + case 188 /* WhileStatement */: + case 187 /* DoStatement */: + if (node.statement.kind !== 182 /* Block */) { report(node, "A looping statement's contents should be wrapped in a block body."); } break; - case 184 /* IfStatement */: + case 186 /* IfStatement */: var ifStatement = node; - if (ifStatement.thenStatement.kind !== 180 /* Block */) { + if (ifStatement.thenStatement.kind !== 182 /* Block */) { report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body."); } if (ifStatement.elseStatement && - ifStatement.elseStatement.kind !== 180 /* Block */ && - ifStatement.elseStatement.kind !== 184 /* IfStatement */) { + ifStatement.elseStatement.kind !== 182 /* Block */ && + ifStatement.elseStatement.kind !== 186 /* IfStatement */) { report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body."); } break; - case 170 /* BinaryExpression */: + case 172 /* BinaryExpression */: var op = node.operatorToken.kind; if (op === 28 /* EqualsEqualsToken */ || op == 29 /* ExclamationEqualsToken */) { report(node, "Use '===' and '!=='."); From f8e2b99b6c0cb94add93d3ac5948130d0e5959fa Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:36 +0800 Subject: [PATCH 04/40] Adds tests --- .../baselines/reference/typeGuardFunction.js | 105 ++++++++++ .../reference/typeGuardFunction.symbols | 144 ++++++++++++++ .../reference/typeGuardFunction.types | 159 +++++++++++++++ .../typeGuardFunctionErrors.errors.txt | 174 ++++++++++++++++ .../reference/typeGuardFunctionErrors.js | 173 ++++++++++++++++ .../reference/typeGuardFunctionGenerics.js | 69 +++++++ .../typeGuardFunctionGenerics.symbols | 125 ++++++++++++ .../reference/typeGuardFunctionGenerics.types | 138 +++++++++++++ .../reference/typeGuardOfFormIsType.js | 85 ++++++++ .../reference/typeGuardOfFormIsType.symbols | 128 ++++++++++++ .../reference/typeGuardOfFormIsType.types | 157 +++++++++++++++ .../typeGuardOfFormIsTypeOnInterfaces.js | 74 +++++++ .../typeGuardOfFormIsTypeOnInterfaces.symbols | 159 +++++++++++++++ .../typeGuardOfFormIsTypeOnInterfaces.types | 188 ++++++++++++++++++ .../typeGuards/typeGuardFunction.ts | 56 ++++++ .../typeGuards/typeGuardFunctionErrors.ts | 92 +++++++++ .../typeGuards/typeGuardFunctionGenerics.ts | 33 +++ .../typeGuards/typeGuardOfFormIsType.ts | 37 ++++ .../typeGuardOfFormIsTypeOnInterfaces.ts | 46 +++++ 19 files changed, 2142 insertions(+) create mode 100644 tests/baselines/reference/typeGuardFunction.js create mode 100644 tests/baselines/reference/typeGuardFunction.symbols create mode 100644 tests/baselines/reference/typeGuardFunction.types create mode 100644 tests/baselines/reference/typeGuardFunctionErrors.errors.txt create mode 100644 tests/baselines/reference/typeGuardFunctionErrors.js create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.js create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.symbols create mode 100644 tests/baselines/reference/typeGuardFunctionGenerics.types create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.js create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormIsType.types create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts diff --git a/tests/baselines/reference/typeGuardFunction.js b/tests/baselines/reference/typeGuardFunction.js new file mode 100644 index 00000000000..d6b64c09d4d --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.js @@ -0,0 +1,105 @@ +//// [typeGuardFunction.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isA(p1: any): p1 is A; +declare function isB(p1: any): p1 is B; +declare function isC(p1: any): p1 is C; + +declare function retC(): C; + +var a: A; +var b: B; + +// Basic. +if (isC(a)) { + a.propC; +} + +// Sub type. +var subType: C; +if(isA(subType)) { + subType.propC; +} + +// Union type. +var union: A | B; +if(isA(union)) { + union.propA; +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +if (isC_multipleParams(a, 0)) { + a.propC; +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +acceptingBoolean(isA(a)); + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +acceptingTypeGuardFunction(isA); + +let union2: C | B; +let union3: boolean | B = isA(union2) || union2; + +//// [typeGuardFunction.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +var a; +var b; +// Basic. +if (isC(a)) { + a.propC; +} +// Sub type. +var subType; +if (isA(subType)) { + subType.propC; +} +// Union type. +var union; +if (isA(union)) { + union.propA; +} +if (isC_multipleParams(a, 0)) { + a.propC; +} +acceptingBoolean(isA(a)); +acceptingTypeGuardFunction(isA); +var union2; +var union3 = isA(union2) || union2; diff --git a/tests/baselines/reference/typeGuardFunction.symbols b/tests/baselines/reference/typeGuardFunction.symbols new file mode 100644 index 00000000000..f9180d56b0b --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.symbols @@ -0,0 +1,144 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts === + +class A { +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + + propA: number; +>propA : Symbol(propA, Decl(typeGuardFunction.ts, 1, 9)) +} + +class B { +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + + propB: number; +>propB : Symbol(propB, Decl(typeGuardFunction.ts, 5, 9)) +} + +class C extends A { +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + + propC: number; +>propC : Symbol(propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +declare function isA(p1: any): p1 is A; +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 13, 21)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +declare function isB(p1: any): p1 is B; +>isB : Symbol(isB, Decl(typeGuardFunction.ts, 13, 39)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 14, 21)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +declare function isC(p1: any): p1 is C; +>isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 15, 21)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +declare function retC(): C; +>retC : Symbol(retC, Decl(typeGuardFunction.ts, 15, 39)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +var a: A; +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +var b: B; +>b : Symbol(b, Decl(typeGuardFunction.ts, 20, 3)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +// Basic. +if (isC(a)) { +>isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Sub type. +var subType: C; +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +if(isA(subType)) { +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) + + subType.propC; +>subType.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Union type. +var union: A | B; +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +if(isA(union)) { +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) + + union.propA; +>union.propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9)) +>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) +>propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9)) +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 36)) +>p2 : Symbol(p2, Decl(typeGuardFunction.ts, 41, 39)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +if (isC_multipleParams(a, 0)) { +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 47, 34)) + +acceptingBoolean(isA(a)); +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 44)) +>item : Symbol(item, Decl(typeGuardFunction.ts, 51, 49)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) + +acceptingTypeGuardFunction(isA); +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) + +let union2: C | B; +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) + +let union3: boolean | B = isA(union2) || union2; +>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 55, 3)) +>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) +>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) + diff --git a/tests/baselines/reference/typeGuardFunction.types b/tests/baselines/reference/typeGuardFunction.types new file mode 100644 index 00000000000..2b3d1c40c8e --- /dev/null +++ b/tests/baselines/reference/typeGuardFunction.types @@ -0,0 +1,159 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts === + +class A { +>A : A + + propA: number; +>propA : number +} + +class B { +>B : B + + propB: number; +>propB : number +} + +class C extends A { +>C : C +>A : A + + propC: number; +>propC : number +} + +declare function isA(p1: any): p1 is A; +>isA : (p1: any) => boolean +>p1 : any +>p1 : any +>A : A + +declare function isB(p1: any): p1 is B; +>isB : (p1: any) => boolean +>p1 : any +>p1 : any +>B : B + +declare function isC(p1: any): p1 is C; +>isC : (p1: any) => boolean +>p1 : any +>p1 : any +>C : C + +declare function retC(): C; +>retC : () => C +>C : C + +var a: A; +>a : A +>A : A + +var b: B; +>b : B +>B : B + +// Basic. +if (isC(a)) { +>isC(a) : boolean +>isC : (p1: any) => boolean +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} + +// Sub type. +var subType: C; +>subType : C +>C : C + +if(isA(subType)) { +>isA(subType) : boolean +>isA : (p1: any) => boolean +>subType : C + + subType.propC; +>subType.propC : number +>subType : C +>propC : number +} + +// Union type. +var union: A | B; +>union : A | B +>A : A +>B : B + +if(isA(union)) { +>isA(union) : boolean +>isA : (p1: any) => boolean +>union : A | B + + union.propA; +>union.propA : number +>union : A +>propA : number +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +>isC_multipleParams : (p1: any, p2: any) => boolean +>p1 : any +>p2 : any +>p1 : any +>C : C + +if (isC_multipleParams(a, 0)) { +>isC_multipleParams(a, 0) : boolean +>isC_multipleParams : (p1: any, p2: any) => boolean +>a : A +>0 : number + + a.propC; +>a.propC : number +>a : C +>propC : number +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +>acceptingBoolean : (a: boolean) => any +>a : boolean + +acceptingBoolean(isA(a)); +>acceptingBoolean(isA(a)) : any +>acceptingBoolean : (a: boolean) => any +>isA(a) : boolean +>isA : (p1: any) => boolean +>a : A + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +>acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any +>p1 : (item: any) => boolean +>item : any +>item : any +>A : A + +acceptingTypeGuardFunction(isA); +>acceptingTypeGuardFunction(isA) : any +>acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any +>isA : (p1: any) => boolean + +let union2: C | B; +>union2 : B | C +>C : C +>B : B + +let union3: boolean | B = isA(union2) || union2; +>union3 : boolean | B +>B : B +>isA(union2) || union2 : boolean | B +>isA(union2) : boolean +>isA : (p1: any) => boolean +>union2 : B | C +>union2 : B + diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt new file mode 100644 index 00000000000..8b5ed551dff --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -0,0 +1,174 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS1225: A type-guard function can only return a boolean. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,60): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,62): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(28,1): error TS1128: Declaration or statement expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,38): error TS1226: Cannot find parameter 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(34,51): error TS2322: Type 'B' is not assignable to type 'A'. + Property 'propA' is missing in type 'B'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(38,56): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(42,56): error TS2322: Type 'T[]' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(56,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(61,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(66,7): error TS2339: Property 'propB' does not exist on type 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(71,46): error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. + Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. + Type 'C' is not assignable to type 'B'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + A non-type guard function is not assignable to a type guard function. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. + Parameter index from 'p2' does not match the parameter index from 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1226: Cannot find parameter 'p1'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (22 errors) ==== + + class A { + propA: number; + } + + class B { + propB: number; + } + + class C extends A { + propC: number; + } + + function hasANonBooleanReturnStatement(x): x is A { + return ''; + ~~ +!!! error TS1225: A type-guard function can only return a boolean. + } + + function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + ~ +!!! error TS2304: Cannot find name 'x'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. + return true; + } + + function hasMissingIsKeyword(): x { + ~ +!!! error TS2304: Cannot find name 'x'. + return true; + } + + function hasMissingTypeInTypeGuardType(x): x is { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2391: Function implementation is missing or not immediately following the declaration. + return true; + ~~~~~~ +!!! error TS1131: Property or signature expected. + } + ~ +!!! error TS1128: Declaration or statement expected. + + function hasNonMatchingParameter(y): x is A { + ~ +!!! error TS1226: Cannot find parameter 'x'. + return true; + } + + function hasNonMatchingParameterType1(x: A): x is B { + ~ +!!! error TS2322: Type 'B' is not assignable to type 'A'. +!!! error TS2322: Property 'propA' is missing in type 'B'. + return true; + } + + function hasNonMatchingParameterType2(x: string): x is number { + ~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + return true; + } + + function hasNonMathcingGenericType(a: string): a is T[] { + ~~~ +!!! error TS2322: Type 'T[]' is not assignable to type 'string'. + return true; + } + + let a: A; + let b: B; + + declare function isB(p1): p1 is B; + declare function isC(p1): p1 is C; + declare function funA(p1: any, p2: any): p1 is B; + declare function hasNoTypeGuard(x); + + // Passed argument is not the same as the one being guarded. + if (isB(b)) { + a.propB; + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // Parameter index and argument index for the type guard target is not matching. + if (funA(0, a)) { + a.propB; // Error + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // No type guard in if statement + if (hasNoTypeGuard(a)) { + a.propB; + ~~~~~ +!!! error TS2339: Property 'propB' does not exist on type 'A'. + } + + // Type predicate type is not assignable + declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); + acceptingDifferentSignatureTypeGuardFunction(isC); + ~~~ +!!! error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. +!!! error TS2345: Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. +!!! error TS2345: Type 'C' is not assignable to type 'B'. + + // Boolean not assignable to type guard + var assign1: (p1, p2) => p1 is A; + assign1 = function(p1, p2): boolean { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +!!! error TS2322: A non-type guard function is not assignable to a type guard function. + return true; + }; + + // Must have matching parameter index + var assign2: (p1, p2) => p1 is A; + assign2 = function(p1, p2): p2 is A { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +!!! error TS2322: Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. +!!! error TS2322: Parameter index from 'p2' does not match the parameter index from 'p1'. + return true; + }; + + // No matching signature + var assign3: (p1, p2) => p1 is A; + assign3 = function(p1, p2, p3): p1 is A { + ~~~~~~~ +!!! error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. + return true; + }; + + // Type guard paramater referring to a binding pattern + declare function destructureParameter({ p1, p2, p3 }): p1 is A; + ~~ +!!! error TS1226: Cannot find parameter 'p1'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js new file mode 100644 index 00000000000..cc65fc00cba --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -0,0 +1,173 @@ +//// [typeGuardFunctionErrors.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +function hasANonBooleanReturnStatement(x): x is A { + return ''; +} + +function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + return true; +} + +function hasMissingIsKeyword(): x { + return true; +} + +function hasMissingTypeInTypeGuardType(x): x is { + return true; +} + +function hasNonMatchingParameter(y): x is A { + return true; +} + +function hasNonMatchingParameterType1(x: A): x is B { + return true; +} + +function hasNonMatchingParameterType2(x: string): x is number { + return true; +} + +function hasNonMathcingGenericType(a: string): a is T[] { + return true; +} + +let a: A; +let b: B; + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function funA(p1: any, p2: any): p1 is B; +declare function hasNoTypeGuard(x); + +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} + +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} + +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} + +// Type predicate type is not assignable +declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); +acceptingDifferentSignatureTypeGuardFunction(isC); + +// Boolean not assignable to type guard +var assign1: (p1, p2) => p1 is A; +assign1 = function(p1, p2): boolean { + return true; +}; + +// Must have matching parameter index +var assign2: (p1, p2) => p1 is A; +assign2 = function(p1, p2): p2 is A { + return true; +}; + +// No matching signature +var assign3: (p1, p2) => p1 is A; +assign3 = function(p1, p2, p3): p1 is A { + return true; +}; + +// Type guard paramater referring to a binding pattern +declare function destructureParameter({ p1, p2, p3 }): p1 is A; + + +//// [typeGuardFunctionErrors.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +function hasANonBooleanReturnStatement(x) { + return ''; +} +is; +A; +{ + return true; +} +function hasMissingIsKeyword() { + return true; +} +return true; +function hasNonMatchingParameter(y) { + return true; +} +function hasNonMatchingParameterType1(x) { + return true; +} +function hasNonMatchingParameterType2(x) { + return true; +} +function hasNonMathcingGenericType(a) { + return true; +} +var a; +var b; +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} +acceptingDifferentSignatureTypeGuardFunction(isC); +// Boolean not assignable to type guard +var assign1; +assign1 = function (p1, p2) { + return true; +}; +// Must have matching parameter index +var assign2; +assign2 = function (p1, p2) { + return true; +}; +// No matching signature +var assign3; +assign3 = function (p1, p2, p3) { + return true; +}; diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.js b/tests/baselines/reference/typeGuardFunctionGenerics.js new file mode 100644 index 00000000000..6704225a0d0 --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.js @@ -0,0 +1,69 @@ +//// [typeGuardFunctionGenerics.ts] + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function retC(x): C; + +declare function funA(p1: (p1) => T): T; +declare function funB(p1: (p1) => T, p2: any): p2 is T; +declare function funC(p1: (p1) => p1 is T): T; +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +declare function funE(p1: (p1) => p1 is T, p2: U): T; + +let a: A; +let test1: boolean = funA(isB); +if (funB(retC, a)) { + a.propC; +} +let test2: B = funC(isB); +if (funD(isC, a)) { + a.propC; +} +let test3: B = funE(isB, 1); + +//// [typeGuardFunctionGenerics.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + return A; +})(); +var B = (function () { + function B() { + } + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})(A); +var a; +var test1 = funA(isB); +if (funB(retC, a)) { + a.propC; +} +var test2 = funC(isB); +if (funD(isC, a)) { + a.propC; +} +var test3 = funE(isB, 1); diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.symbols b/tests/baselines/reference/typeGuardFunctionGenerics.symbols new file mode 100644 index 00000000000..0ad8fab2fdb --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.symbols @@ -0,0 +1,125 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts === + +class A { +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + + propA: number; +>propA : Symbol(propA, Decl(typeGuardFunctionGenerics.ts, 1, 9)) +} + +class B { +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) + + propB: number; +>propB : Symbol(propB, Decl(typeGuardFunctionGenerics.ts, 5, 9)) +} + +class C extends A { +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + + propC: number; +>propC : Symbol(propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} + +declare function isB(p1): p1 is B; +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 13, 21)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) + +declare function isC(p1): p1 is C; +>isC : Symbol(isC, Decl(typeGuardFunctionGenerics.ts, 13, 34)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 14, 21)) +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) + +declare function retC(x): C; +>retC : Symbol(retC, Decl(typeGuardFunctionGenerics.ts, 14, 34)) +>x : Symbol(x, Decl(typeGuardFunctionGenerics.ts, 15, 22)) +>C : Symbol(C, Decl(typeGuardFunctionGenerics.ts, 7, 1)) + +declare function funA(p1: (p1) => T): T; +>funA : Symbol(funA, Decl(typeGuardFunctionGenerics.ts, 15, 28)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 17, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 17, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 17, 22)) + +declare function funB(p1: (p1) => T, p2: any): p2 is T; +>funB : Symbol(funB, Decl(typeGuardFunctionGenerics.ts, 17, 43)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 18, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 18, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 18, 39)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 18, 22)) + +declare function funC(p1: (p1) => p1 is T): T; +>funC : Symbol(funC, Decl(typeGuardFunctionGenerics.ts, 18, 58)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 19, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 19, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 19, 22)) + +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +>funD : Symbol(funD, Decl(typeGuardFunctionGenerics.ts, 19, 49)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 20, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 20, 30)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 20, 45)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 20, 22)) + +declare function funE(p1: (p1) => p1 is T, p2: U): T; +>funE : Symbol(funE, Decl(typeGuardFunctionGenerics.ts, 20, 64)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) +>U : Symbol(U, Decl(typeGuardFunctionGenerics.ts, 21, 24)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 21, 28)) +>p1 : Symbol(p1, Decl(typeGuardFunctionGenerics.ts, 21, 33)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) +>p2 : Symbol(p2, Decl(typeGuardFunctionGenerics.ts, 21, 48)) +>U : Symbol(U, Decl(typeGuardFunctionGenerics.ts, 21, 24)) +>T : Symbol(T, Decl(typeGuardFunctionGenerics.ts, 21, 22)) + +let a: A; +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>A : Symbol(A, Decl(typeGuardFunctionGenerics.ts, 0, 0)) + +let test1: boolean = funA(isB); +>test1 : Symbol(test1, Decl(typeGuardFunctionGenerics.ts, 24, 3)) +>funA : Symbol(funA, Decl(typeGuardFunctionGenerics.ts, 15, 28)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + +if (funB(retC, a)) { +>funB : Symbol(funB, Decl(typeGuardFunctionGenerics.ts, 17, 43)) +>retC : Symbol(retC, Decl(typeGuardFunctionGenerics.ts, 14, 34)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} +let test2: B = funC(isB); +>test2 : Symbol(test2, Decl(typeGuardFunctionGenerics.ts, 28, 3)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) +>funC : Symbol(funC, Decl(typeGuardFunctionGenerics.ts, 18, 58)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + +if (funD(isC, a)) { +>funD : Symbol(funD, Decl(typeGuardFunctionGenerics.ts, 19, 49)) +>isC : Symbol(isC, Decl(typeGuardFunctionGenerics.ts, 13, 34)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) + + a.propC; +>a.propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +>a : Symbol(a, Decl(typeGuardFunctionGenerics.ts, 23, 3)) +>propC : Symbol(C.propC, Decl(typeGuardFunctionGenerics.ts, 9, 19)) +} +let test3: B = funE(isB, 1); +>test3 : Symbol(test3, Decl(typeGuardFunctionGenerics.ts, 32, 3)) +>B : Symbol(B, Decl(typeGuardFunctionGenerics.ts, 3, 1)) +>funE : Symbol(funE, Decl(typeGuardFunctionGenerics.ts, 20, 64)) +>isB : Symbol(isB, Decl(typeGuardFunctionGenerics.ts, 11, 1)) + diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.types b/tests/baselines/reference/typeGuardFunctionGenerics.types new file mode 100644 index 00000000000..77162e55a40 --- /dev/null +++ b/tests/baselines/reference/typeGuardFunctionGenerics.types @@ -0,0 +1,138 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts === + +class A { +>A : A + + propA: number; +>propA : number +} + +class B { +>B : B + + propB: number; +>propB : number +} + +class C extends A { +>C : C +>A : A + + propC: number; +>propC : number +} + +declare function isB(p1): p1 is B; +>isB : (p1: any) => boolean +>p1 : any +>p1 : any +>B : B + +declare function isC(p1): p1 is C; +>isC : (p1: any) => boolean +>p1 : any +>p1 : any +>C : C + +declare function retC(x): C; +>retC : (x: any) => C +>x : any +>C : C + +declare function funA(p1: (p1) => T): T; +>funA : (p1: (p1: any) => T) => T +>T : T +>p1 : (p1: any) => T +>p1 : any +>T : T +>T : T + +declare function funB(p1: (p1) => T, p2: any): p2 is T; +>funB : (p1: (p1: any) => T, p2: any) => boolean +>T : T +>p1 : (p1: any) => T +>p1 : any +>T : T +>p2 : any +>p2 : any +>T : T + +declare function funC(p1: (p1) => p1 is T): T; +>funC : (p1: (p1: any) => boolean) => T +>T : T +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>T : T + +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +>funD : (p1: (p1: any) => boolean, p2: any) => boolean +>T : T +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>p2 : any +>p2 : any +>T : T + +declare function funE(p1: (p1) => p1 is T, p2: U): T; +>funE : (p1: (p1: any) => boolean, p2: U) => T +>T : T +>U : U +>p1 : (p1: any) => boolean +>p1 : any +>p1 : any +>T : T +>p2 : U +>U : U +>T : T + +let a: A; +>a : A +>A : A + +let test1: boolean = funA(isB); +>test1 : boolean +>funA(isB) : boolean +>funA : (p1: (p1: any) => T) => T +>isB : (p1: any) => boolean + +if (funB(retC, a)) { +>funB(retC, a) : boolean +>funB : (p1: (p1: any) => T, p2: any) => boolean +>retC : (x: any) => C +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} +let test2: B = funC(isB); +>test2 : B +>B : B +>funC(isB) : B +>funC : (p1: (p1: any) => boolean) => T +>isB : (p1: any) => boolean + +if (funD(isC, a)) { +>funD(isC, a) : boolean +>funD : (p1: (p1: any) => boolean, p2: any) => boolean +>isC : (p1: any) => boolean +>a : A + + a.propC; +>a.propC : number +>a : C +>propC : number +} +let test3: B = funE(isB, 1); +>test3 : B +>B : B +>funE(isB, 1) : B +>funE : (p1: (p1: any) => boolean, p2: U) => T +>isB : (p1: any) => boolean +>1 : number + diff --git a/tests/baselines/reference/typeGuardOfFormIsType.js b/tests/baselines/reference/typeGuardOfFormIsType.js new file mode 100644 index 00000000000..65d99319d1e --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.js @@ -0,0 +1,85 @@ +//// [typeGuardOfFormIsType.ts] + +class C1 { + p1: string; +} +class C2 { + p2: number; +} +class D1 extends C1 { + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 + +//// [typeGuardOfFormIsType.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C1 = (function () { + function C1() { + } + return C1; +})(); +var C2 = (function () { + function C2() { + } + return C2; +})(); +var D1 = (function (_super) { + __extends(D1, _super); + function D1() { + _super.apply(this, arguments); + } + return D1; +})(C1); +var str; +var num; +var strOrNum; +function isC1(x) { + return true; +} +function isC2(x) { + return true; +} +function isD1(x) { + return true; +} +var c1Orc2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +var c2Ord1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2 = isC1(c2Ord1) && c2Ord1; // C2 | D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsType.symbols b/tests/baselines/reference/typeGuardOfFormIsType.symbols new file mode 100644 index 00000000000..a7bd0f4c165 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.symbols @@ -0,0 +1,128 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts === + +class C1 { +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + p1: string; +>p1 : Symbol(p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +} +class C2 { +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + + p2: number; +>p2 : Symbol(p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +} +class D1 extends C1 { +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + p3: number; +>p3 : Symbol(p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +} +var str: string; +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) + +var num: number; +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) + +var strOrNum: string | number; +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormIsType.ts, 12, 3)) + +function isC1(x: any): x is C1 { +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 14, 14)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) + + return true; +} + +function isC2(x: any): x is C2 { +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 18, 14)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + + return true; +} + +function isD1(x: any): x is D1 { +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsType.ts, 22, 14)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) + + return true; +} + +var c1Orc2: C1 | C2; +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsType.ts, 0, 0)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>c1Orc2.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsType.ts, 26, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) + +var c2Ord1: C2 | D1; +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsType.ts, 16, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsType.ts, 4, 10)) + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsType.ts, 11, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsType.ts, 7, 21)) + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsType.ts, 10, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsType.ts, 20, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsType.ts, 1, 10)) + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : Symbol(r2, Decl(typeGuardOfFormIsType.ts, 36, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsType.ts, 3, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsType.ts, 6, 1)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsType.ts, 12, 30)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsType.ts, 32, 3)) + diff --git a/tests/baselines/reference/typeGuardOfFormIsType.types b/tests/baselines/reference/typeGuardOfFormIsType.types new file mode 100644 index 00000000000..b14e5e22910 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsType.types @@ -0,0 +1,157 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts === + +class C1 { +>C1 : C1 + + p1: string; +>p1 : string +} +class C2 { +>C2 : C2 + + p2: number; +>p2 : number +} +class D1 extends C1 { +>D1 : D1 +>C1 : C1 + + p3: number; +>p3 : number +} +var str: string; +>str : string + +var num: number; +>num : number + +var strOrNum: string | number; +>strOrNum : string | number + +function isC1(x: any): x is C1 { +>isC1 : (x: any) => boolean +>x : any +>x : any +>C1 : C1 + + return true; +>true : boolean +} + +function isC2(x: any): x is C2 { +>isC2 : (x: any) => boolean +>x : any +>x : any +>C2 : C2 + + return true; +>true : boolean +} + +function isD1(x: any): x is D1 { +>isD1 : (x: any) => boolean +>x : any +>x : any +>D1 : D1 + + return true; +>true : boolean +} + +var c1Orc2: C1 | C2; +>c1Orc2 : C1 | C2 +>C1 : C1 +>C2 : C2 + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str = isC1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isC1(c1Orc2) && c1Orc2.p1 : string +>isC1(c1Orc2) : boolean +>isC1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : C1 +>p1 : string + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num = isC2(c1Orc2) && c1Orc2.p2 : number +>num : number +>isC2(c1Orc2) && c1Orc2.p2 : number +>isC2(c1Orc2) : boolean +>isC2 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p2 : number +>c1Orc2 : C2 +>p2 : number + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str = isD1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isD1(c1Orc2) && c1Orc2.p1 : string +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : D1 +>p1 : string + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num = isD1(c1Orc2) && c1Orc2.p3 : number +>num : number +>isD1(c1Orc2) && c1Orc2.p3 : number +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p3 : number +>c1Orc2 : D1 +>p3 : number + +var c2Ord1: C2 | D1; +>c2Ord1 : C2 | D1 +>C2 : C2 +>D1 : D1 + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num = isC2(c2Ord1) && c2Ord1.p2 : number +>num : number +>isC2(c2Ord1) && c2Ord1.p2 : number +>isC2(c2Ord1) : boolean +>isC2 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p2 : number +>c2Ord1 : C2 +>p2 : number + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num = isD1(c2Ord1) && c2Ord1.p3 : number +>num : number +>isD1(c2Ord1) && c2Ord1.p3 : number +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p3 : number +>c2Ord1 : D1 +>p3 : number + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str = isD1(c2Ord1) && c2Ord1.p1 : string +>str : string +>isD1(c2Ord1) && c2Ord1.p1 : string +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p1 : string +>c2Ord1 : D1 +>p1 : string + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : C2 | D1 +>C2 : C2 +>D1 : D1 +>isC1(c2Ord1) && c2Ord1 : D1 +>isC1(c2Ord1) : boolean +>isC1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1 : D1 + diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js new file mode 100644 index 00000000000..d5faee96e8b --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.js @@ -0,0 +1,74 @@ +//// [typeGuardOfFormIsTypeOnInterfaces.ts] + +interface C1 { + (): C1; + prototype: C1; + p1: string; +} +interface C2 { + (): C2; + prototype: C2; + p2: number; +} +interface D1 extends C1 { + prototype: D1; + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1: C1; +var c2: C2; +var d1: D1; +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 + +//// [typeGuardOfFormIsTypeOnInterfaces.js] +var str; +var num; +var strOrNum; +function isC1(x) { + return true; +} +function isC2(x) { + return true; +} +function isD1(x) { + return true; +} +var c1; +var c2; +var d1; +var c1Orc2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +var c2Ord1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2 = isC1(c2Ord1) && c2Ord1; // C2 | D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols new file mode 100644 index 00000000000..37249ef7659 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.symbols @@ -0,0 +1,159 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts === + +interface C1 { +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + (): C1; +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + prototype: C1; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 2, 11)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + p1: string; +>p1 : Symbol(p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +} +interface C2 { +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + (): C2; +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + prototype: C2; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 7, 11)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + p2: number; +>p2 : Symbol(p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +} +interface D1 extends C1 { +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + prototype: D1; +>prototype : Symbol(prototype, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 11, 25)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + + p3: number; +>p3 : Symbol(p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +} +var str: string; +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) + +var num: number; +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) + +var strOrNum: string | number; +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 3)) + + +function isC1(x: any): x is C1 { +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 20, 14)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + + return true; +} + +function isC2(x: any): x is C2 { +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 24, 14)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + + return true; +} + +function isD1(x: any): x is D1 { +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>x : Symbol(x, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 28, 14)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + + return true; +} + +var c1: C1; +>c1 : Symbol(c1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 32, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) + +var c2: C2; +>c2 : Symbol(c2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 33, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + +var d1: D1; +>d1 : Symbol(d1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 34, 3)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + +var c1Orc2: C1 | C2; +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>C1 : Symbol(C1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 0, 0)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>c1Orc2.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +>c1Orc2 : Symbol(c1Orc2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 35, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) + +var c2Ord1: C2 | D1; +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isC2 : Symbol(isC2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 22, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p2 : Symbol(C2.p2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 8, 18)) + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num : Symbol(num, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 16, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p3 : Symbol(D1.p3, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 12, 18)) + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str : Symbol(str, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 15, 3)) +>isD1 : Symbol(isD1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 26, 1)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1.p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>p1 : Symbol(C1.p1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 3, 18)) + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : Symbol(r2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 45, 3)) +>C2 : Symbol(C2, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 5, 1)) +>D1 : Symbol(D1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 10, 1)) +>isC1 : Symbol(isC1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 17, 30)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) +>c2Ord1 : Symbol(c2Ord1, Decl(typeGuardOfFormIsTypeOnInterfaces.ts, 41, 3)) + diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types new file mode 100644 index 00000000000..3a659d71163 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types @@ -0,0 +1,188 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts === + +interface C1 { +>C1 : C1 + + (): C1; +>C1 : C1 + + prototype: C1; +>prototype : C1 +>C1 : C1 + + p1: string; +>p1 : string +} +interface C2 { +>C2 : C2 + + (): C2; +>C2 : C2 + + prototype: C2; +>prototype : C2 +>C2 : C2 + + p2: number; +>p2 : number +} +interface D1 extends C1 { +>D1 : D1 +>C1 : C1 + + prototype: D1; +>prototype : D1 +>D1 : D1 + + p3: number; +>p3 : number +} +var str: string; +>str : string + +var num: number; +>num : number + +var strOrNum: string | number; +>strOrNum : string | number + + +function isC1(x: any): x is C1 { +>isC1 : (x: any) => boolean +>x : any +>x : any +>C1 : C1 + + return true; +>true : boolean +} + +function isC2(x: any): x is C2 { +>isC2 : (x: any) => boolean +>x : any +>x : any +>C2 : C2 + + return true; +>true : boolean +} + +function isD1(x: any): x is D1 { +>isD1 : (x: any) => boolean +>x : any +>x : any +>D1 : D1 + + return true; +>true : boolean +} + +var c1: C1; +>c1 : C1 +>C1 : C1 + +var c2: C2; +>c2 : C2 +>C2 : C2 + +var d1: D1; +>d1 : D1 +>D1 : D1 + +var c1Orc2: C1 | C2; +>c1Orc2 : C1 | C2 +>C1 : C1 +>C2 : C2 + +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +>str = isC1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isC1(c1Orc2) && c1Orc2.p1 : string +>isC1(c1Orc2) : boolean +>isC1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : C1 +>p1 : string + +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +>num = isC2(c1Orc2) && c1Orc2.p2 : number +>num : number +>isC2(c1Orc2) && c1Orc2.p2 : number +>isC2(c1Orc2) : boolean +>isC2 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p2 : number +>c1Orc2 : C2 +>p2 : number + +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +>str = isD1(c1Orc2) && c1Orc2.p1 : string +>str : string +>isD1(c1Orc2) && c1Orc2.p1 : string +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p1 : string +>c1Orc2 : D1 +>p1 : string + +num = isD1(c1Orc2) && c1Orc2.p3; // D1 +>num = isD1(c1Orc2) && c1Orc2.p3 : number +>num : number +>isD1(c1Orc2) && c1Orc2.p3 : number +>isD1(c1Orc2) : boolean +>isD1 : (x: any) => boolean +>c1Orc2 : C1 | C2 +>c1Orc2.p3 : number +>c1Orc2 : D1 +>p3 : number + +var c2Ord1: C2 | D1; +>c2Ord1 : C2 | D1 +>C2 : C2 +>D1 : D1 + +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +>num = isC2(c2Ord1) && c2Ord1.p2 : number +>num : number +>isC2(c2Ord1) && c2Ord1.p2 : number +>isC2(c2Ord1) : boolean +>isC2 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p2 : number +>c2Ord1 : C2 +>p2 : number + +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +>num = isD1(c2Ord1) && c2Ord1.p3 : number +>num : number +>isD1(c2Ord1) && c2Ord1.p3 : number +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p3 : number +>c2Ord1 : D1 +>p3 : number + +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +>str = isD1(c2Ord1) && c2Ord1.p1 : string +>str : string +>isD1(c2Ord1) && c2Ord1.p1 : string +>isD1(c2Ord1) : boolean +>isD1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1.p1 : string +>c2Ord1 : D1 +>p1 : string + +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 +>r2 : C2 | D1 +>C2 : C2 +>D1 : D1 +>isC1(c2Ord1) && c2Ord1 : D1 +>isC1(c2Ord1) : boolean +>isC1 : (x: any) => boolean +>c2Ord1 : C2 | D1 +>c2Ord1 : D1 + diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts new file mode 100644 index 00000000000..93cfd90ceb5 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts @@ -0,0 +1,56 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isA(p1: any): p1 is A; +declare function isB(p1: any): p1 is B; +declare function isC(p1: any): p1 is C; + +declare function retC(): C; + +var a: A; +var b: B; + +// Basic. +if (isC(a)) { + a.propC; +} + +// Sub type. +var subType: C; +if(isA(subType)) { + subType.propC; +} + +// Union type. +var union: A | B; +if(isA(union)) { + union.propA; +} + +// The parameter index and argument index for the type guard target is matching. +// The type predicate type is assignable to the parameter type. +declare function isC_multipleParams(p1, p2): p1 is C; +if (isC_multipleParams(a, 0)) { + a.propC; +} + +// Evaluations are asssignable to boolean. +declare function acceptingBoolean(a: boolean); +acceptingBoolean(isA(a)); + +// Type predicates with different parameter name. +declare function acceptingTypeGuardFunction(p1: (item) => item is A); +acceptingTypeGuardFunction(isA); + +let union2: C | B; +let union3: boolean | B = isA(union2) || union2; \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts new file mode 100644 index 00000000000..28a512aca6d --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -0,0 +1,92 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +function hasANonBooleanReturnStatement(x): x is A { + return ''; +} + +function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + return true; +} + +function hasMissingIsKeyword(): x { + return true; +} + +function hasMissingTypeInTypeGuardType(x): x is { + return true; +} + +function hasNonMatchingParameter(y): x is A { + return true; +} + +function hasNonMatchingParameterType1(x: A): x is B { + return true; +} + +function hasNonMatchingParameterType2(x: string): x is number { + return true; +} + +function hasNonMathcingGenericType(a: string): a is T[] { + return true; +} + +let a: A; +let b: B; + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function funA(p1: any, p2: any): p1 is B; +declare function hasNoTypeGuard(x); + +// Passed argument is not the same as the one being guarded. +if (isB(b)) { + a.propB; +} + +// Parameter index and argument index for the type guard target is not matching. +if (funA(0, a)) { + a.propB; // Error +} + +// No type guard in if statement +if (hasNoTypeGuard(a)) { + a.propB; +} + +// Type predicate type is not assignable +declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B); +acceptingDifferentSignatureTypeGuardFunction(isC); + +// Boolean not assignable to type guard +var assign1: (p1, p2) => p1 is A; +assign1 = function(p1, p2): boolean { + return true; +}; + +// Must have matching parameter index +var assign2: (p1, p2) => p1 is A; +assign2 = function(p1, p2): p2 is A { + return true; +}; + +// No matching signature +var assign3: (p1, p2) => p1 is A; +assign3 = function(p1, p2, p3): p1 is A { + return true; +}; + +// Type guard paramater referring to a binding pattern +declare function destructureParameter({ p1, p2, p3 }): p1 is A; diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts new file mode 100644 index 00000000000..d0e108b5735 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionGenerics.ts @@ -0,0 +1,33 @@ + +class A { + propA: number; +} + +class B { + propB: number; +} + +class C extends A { + propC: number; +} + +declare function isB(p1): p1 is B; +declare function isC(p1): p1 is C; +declare function retC(x): C; + +declare function funA(p1: (p1) => T): T; +declare function funB(p1: (p1) => T, p2: any): p2 is T; +declare function funC(p1: (p1) => p1 is T): T; +declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; +declare function funE(p1: (p1) => p1 is T, p2: U): T; + +let a: A; +let test1: boolean = funA(isB); +if (funB(retC, a)) { + a.propC; +} +let test2: B = funC(isB); +if (funD(isC, a)) { + a.propC; +} +let test3: B = funE(isB, 1); \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts new file mode 100644 index 00000000000..9f5ca611ee9 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsType.ts @@ -0,0 +1,37 @@ + +class C1 { + p1: string; +} +class C2 { + p2: number; +} +class D1 extends C1 { + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts new file mode 100644 index 00000000000..a199aeb1e68 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormIsTypeOnInterfaces.ts @@ -0,0 +1,46 @@ + +interface C1 { + (): C1; + prototype: C1; + p1: string; +} +interface C2 { + (): C2; + prototype: C2; + p2: number; +} +interface D1 extends C1 { + prototype: D1; + p3: number; +} +var str: string; +var num: number; +var strOrNum: string | number; + + +function isC1(x: any): x is C1 { + return true; +} + +function isC2(x: any): x is C2 { + return true; +} + +function isD1(x: any): x is D1 { + return true; +} + +var c1: C1; +var c2: C2; +var d1: D1; +var c1Orc2: C1 | C2; +str = isC1(c1Orc2) && c1Orc2.p1; // C1 +num = isC2(c1Orc2) && c1Orc2.p2; // C2 +str = isD1(c1Orc2) && c1Orc2.p1; // D1 +num = isD1(c1Orc2) && c1Orc2.p3; // D1 + +var c2Ord1: C2 | D1; +num = isC2(c2Ord1) && c2Ord1.p2; // C2 +num = isD1(c2Ord1) && c2Ord1.p3; // D1 +str = isD1(c2Ord1) && c2Ord1.p1; // D1 +var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 \ No newline at end of file From b7d1df68fb21703e529a2600bf42ad0ce3f6b9be Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 23:25:21 +0800 Subject: [PATCH 05/40] Adds type guard methods --- src/compiler/checker.ts | 48 ++++-- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 4 + src/compiler/parser.ts | 42 ++++-- .../reference/typeGuardMethods.errors.txt | 73 +++++++++ tests/baselines/reference/typeGuardMethods.js | 141 ++++++++++++++++++ .../typeGuards/typeGuardMethods.ts | 64 ++++++++ 7 files changed, 350 insertions(+), 23 deletions(-) create mode 100644 tests/baselines/reference/typeGuardMethods.errors.txt create mode 100644 tests/baselines/reference/typeGuardMethods.js create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a09a2736aac..5a33748fb0b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5646,6 +5646,24 @@ module ts { return type; } + function shouldNarrowTypeByTypePredicate(signature: Signature, expr: CallExpression): boolean { + if (!signature.typePredicate) { + return false; + } + if (expr.arguments && + expr.arguments[signature.typePredicate.parameterIndex] && + getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + + return true; + } + if (expr.expression.kind === SyntaxKind.PropertyAccessExpression && + getSymbolAtLocation((expr.expression).expression) === symbol) { + + return true; + } + return false; + } + function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { if (type.flags & TypeFlags.Any) { return type; @@ -5657,16 +5675,12 @@ module ts { } return type; } - if (signature.typePredicate) { - if (expr.arguments && expr.arguments[signature.typePredicate.parameterIndex]) { - if (getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { - if (isTypeSubtypeOf(signature.typePredicate.type, type)) { - return signature.typePredicate.type; - } - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); - } - } + if (shouldNarrowTypeByTypePredicate(signature, expr)) { + if (isTypeSubtypeOf(signature.typePredicate.type, type)) { + return signature.typePredicate.type; + } + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); } } return type; @@ -8622,8 +8636,7 @@ module ts { links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type); } if (links.typePredicateParameterIndex >= 0) { - checkTypeAssignableTo( - links.typeFromTypePredicate, + checkTypeAssignableTo(links.typeFromTypePredicate, getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), node.typePredicate.type); } @@ -8632,6 +8645,17 @@ module ts { Diagnostics.Cannot_find_parameter_0, node.typePredicate.parameterName.text); } + else { + let typeOfClass = getTypeAtLocation(node.parent); + if (!isTypeSubtypeOf(links.typeFromTypePredicate, typeOfClass) && + !isTypeSubtypeOf(typeOfClass, links.typeFromTypePredicate)) { + + error(node.typePredicate, + Diagnostics.Type_0_and_type_1_are_disjoint_types, + typeToString(links.typeFromTypePredicate), + typeToString(typeOfClass)); + } + } } if (produceDiagnostics) { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 5a87f67ddd3..aba138b9a1b 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -184,6 +184,7 @@ module ts { Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, + Type_0_and_type_1_are_disjoint_types: { code: 1229, category: DiagnosticCategory.Error, key: "Type '{0}' and type '{1}' are disjoint types." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0053b071438..a94839fba7d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -723,6 +723,10 @@ "category": "Error", "code": 1228 }, + "Type '{0}' and type '{1}' are disjoint types.": { + "category": "Error", + "code": 1229 + }, "Duplicate identifier '{0}'.": { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac4517a0b79..0f84ec20383 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2014,6 +2014,34 @@ module ts { return parseInitializer(/*inParameter*/ true); } + function parseTypePredicate(signature: SignatureDeclaration) { + let node = createNode(SyntaxKind.TypePredicate); + if (token !== SyntaxKind.ThisKeyword) { + node.pos = signature.type.pos; + node.parameterName = (signature.type).typeName; + signature.type = undefined; + } + else { + // Swallow `this` + nextToken(); + } + + // Swallow `is` + nextToken(); + + node.type = parseType(); + signature.typePredicate = finishNode(node); + } + + function parseTypePredicateOrReturnType(signature: SignatureDeclaration) { + if (token === SyntaxKind.ThisKeyword) { + parseTypePredicate(signature); + } + else { + signature.type = parseType(); + } + } + function fillSignature( returnToken: SyntaxKind, yieldAndGeneratorParameterContext: boolean, @@ -2025,21 +2053,13 @@ module ts { if (returnTokenRequired) { parseExpected(returnToken); - signature.type = parseType(); + parseTypePredicateOrReturnType(signature); } else if (parseOptional(returnToken)) { - signature.type = parseType(); + parseTypePredicateOrReturnType(signature); } if (token === SyntaxKind.IsKeyword) { - let node = createNode(SyntaxKind.TypePredicate); - node.pos = signature.type.pos; - node.parameterName = (signature.type).typeName; - - nextToken(); - - node.type = parseType(); - signature.type = undefined; - signature.typePredicate = finishNode(node); + parseTypePredicate(signature); } } diff --git a/tests/baselines/reference/typeGuardMethods.errors.txt b/tests/baselines/reference/typeGuardMethods.errors.txt new file mode 100644 index 00000000000..246f84ccc09 --- /dev/null +++ b/tests/baselines/reference/typeGuardMethods.errors.txt @@ -0,0 +1,73 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(14,12): error TS1229: Type 'A' and type 'B' are disjoint types. +tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(17,12): error TS1229: Type 'C' and type 'B' are disjoint types. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts (2 errors) ==== + + class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } + } + + class B { + propB: number; + isA(): this is A { + ~~~~~~~~~ +!!! error TS1229: Type 'A' and type 'B' are disjoint types. + return false; + } + isC(): this is C { + ~~~~~~~~~ +!!! error TS1229: Type 'C' and type 'B' are disjoint types. + return false; + } + } + + class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } + } + + class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } + } + + var a: A; + + // Basic. + if (a.isC()) { + a.propC; + } + + // Sub type. + var subType: C; + if(subType.isA()) { + subType.propC; + } + + // Union type. + var union: A | B; + if(union.isA()) { + union.propA; + } + + var b: any; + var d = new D; + if(d.isString(b)) { + b.length; + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardMethods.js b/tests/baselines/reference/typeGuardMethods.js new file mode 100644 index 00000000000..dcc7eca43c9 --- /dev/null +++ b/tests/baselines/reference/typeGuardMethods.js @@ -0,0 +1,141 @@ +//// [typeGuardMethods.ts] + +class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } +} + +class B { + propB: number; + isA(): this is A { + return false; + } + isC(): this is C { + return false; + } +} + +class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } +} + +class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } +} + +var a: A; + +// Basic. +if (a.isC()) { + a.propC; +} + +// Sub type. +var subType: C; +if(subType.isA()) { + subType.propC; +} + +// Union type. +var union: A | B; +if(union.isA()) { + union.propA; +} + +var b: any; +var d = new D; +if(d.isString(b)) { + b.length; +} + +//// [typeGuardMethods.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A() { + } + A.prototype.isA = function () { + return true; + }; + A.prototype.isC = function () { + return false; + }; + return A; +})(); +var B = (function () { + function B() { + } + B.prototype.isA = function () { + return false; + }; + B.prototype.isC = function () { + return false; + }; + return B; +})(); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + C.prototype.isA = function () { + return false; + }; + C.prototype.isC = function () { + return true; + }; + return C; +})(A); +var D = (function (_super) { + __extends(D, _super); + function D() { + _super.apply(this, arguments); + } + D.prototype.isA = function () { + return false; + }; + D.prototype.isString = function (x) { + return true; + }; + return D; +})(C); +var a; +// Basic. +if (a.isC()) { + a.propC; +} +// Sub type. +var subType; +if (subType.isA()) { + subType.propC; +} +// Union type. +var union; +if (union.isA()) { + union.propA; +} +var b; +var d = new D; +if (d.isString(b)) { + b.length; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts new file mode 100644 index 00000000000..80ae65a7ddb --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts @@ -0,0 +1,64 @@ + +class A { + propA: number; + isA(): this is A { + return true; + } + isC(): this is C { + return false; + } +} + +class B { + propB: number; + isA(): this is A { + return false; + } + isC(): this is C { + return false; + } +} + +class C extends A { + propC: number; + isA(): this is A { + return false; + } + isC(): this is C { + return true; + } +} + +class D extends C { + isA(): this is A { + return false; + } + isString(x: any): x is string { // with parameter declaration + return true; + } +} + +var a: A; + +// Basic. +if (a.isC()) { + a.propC; +} + +// Sub type. +var subType: C; +if(subType.isA()) { + subType.propC; +} + +// Union type. +var union: A | B; +if(union.isA()) { + union.propA; +} + +var b: any; +var d = new D; +if(d.isString(b)) { + b.length; +} \ No newline at end of file From b0542342c38749367530d7b6d400b7824795286c Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Wed, 3 Jun 2015 15:29:06 +0800 Subject: [PATCH 06/40] Addresses PR feedback --- src/compiler/checker.ts | 100 ++++++++++-------- .../diagnosticInformationMap.generated.ts | 4 +- src/compiler/diagnosticMessages.json | 4 +- .../typeGuardFunctionErrors.errors.txt | 16 +-- 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5a33748fb0b..80477ea1841 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3231,7 +3231,10 @@ module ts { let returnType: Type; let typePredicate: TypePredicate; - if (declaration.typePredicate) { + if (classType) { + returnType = classType; + } + else if (declaration.typePredicate) { returnType = booleanType; let typePredicateNode = declaration.typePredicate; let links = getNodeLinks(typePredicateNode); @@ -3242,14 +3245,11 @@ module ts { links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type); } typePredicate = { - parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, - parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, - type: links.typeFromTypePredicate + parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, + parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, + type: links.typeFromTypePredicate }; } - else if (classType) { - returnType = classType; - } else if (declaration.type) { returnType = getTypeFromTypeNode(declaration.type); } @@ -3976,17 +3976,22 @@ module ts { function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { let freshTypeParameters: TypeParameter[]; + let freshTypePredicate: TypePredicate; if (signature.typeParameters && !eraseTypeParameters) { freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter); mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper); } if (signature.typePredicate) { - signature.typePredicate.type = instantiateType(signature.typePredicate.type, mapper); + freshTypePredicate = { + parameterName: signature.typePredicate.parameterName, + parameterIndex: signature.typePredicate.parameterIndex, + type: instantiateType(signature.typePredicate.type, mapper) + } } let result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined, - signature.typePredicate, + freshTypePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); result.target = signature; result.mapper = mapper; @@ -4656,33 +4661,33 @@ module ts { } if (source.typePredicate && target.typePredicate) { - if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex || - source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { - + let hasDifferentParamaterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex; + let hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type); + if (hasDifferentParamaterIndex || hasDifferentTypes) { if (reportErrors) { let sourceParamText = source.typePredicate.parameterName; let targetParamText = target.typePredicate.parameterName; let sourceTypeText = typeToString(source.typePredicate.type); let targetTypeText = typeToString(target.typePredicate.type); - if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex) { - reportError(Diagnostics.Parameter_index_from_0_does_not_match_the_parameter_index_from_1, + if (hasDifferentParamaterIndex) { + reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceParamText, targetParamText); } - if (source.typePredicate.type.symbol !== target.typePredicate.type.symbol) { + if (hasDifferentTypes) { reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, sourceTypeText, targetTypeText); } - reportError(Diagnostics.Type_guard_annotation_0_is_not_assignable_to_1, + reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, `${sourceParamText} is ${sourceTypeText}`, `${targetParamText} is ${targetTypeText}`); } - return Ternary.False; } + return Ternary.True; } else if (!source.typePredicate && target.typePredicate) { if (reportErrors) { @@ -5223,12 +5228,15 @@ module ts { function inferFromSignature(source: Signature, target: Signature) { forEachMatchingParameterType(source, target, inferFromTypes); - if (source.typePredicate && - target.typePredicate && - target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { - - inferFromTypes(source.typePredicate.type, target.typePredicate.type); - return; + if (source.typePredicate && target.typePredicate) { + if (target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { + // Return types from type predicates are treated as booleans. In order to infer types + // from type predicates we would need infer from the type from type predicates. Since + // we can't infer any type information from the return types. We can just add a return + // statement after the below infer statement. + inferFromTypes(source.typePredicate.type, target.typePredicate.type); + return; + } } inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } @@ -5633,19 +5641,24 @@ module ts { } if (targetType) { - // Narrow to the target type if it's a subtype of the current type - if (isTypeSubtypeOf(targetType, type)) { - return targetType; - } - // If the current type is a union type, remove all constituents that aren't subtypes of the target. - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, targetType))); - } + return getOptionalNarrowedType(type, targetType); } return type; } + function getOptionalNarrowedType(originalType: Type, narrowedTypeCandidate: Type) { + // Narrow to the target type if it's a subtype of the current type + if (isTypeSubtypeOf(narrowedTypeCandidate, originalType)) { + return narrowedTypeCandidate; + } + // If the current type is a union type, remove all constituents that aren't subtypes of the target. + if (originalType.flags & TypeFlags.Union) { + return getUnionType(filter((originalType).types, t => isTypeSubtypeOf(t, narrowedTypeCandidate))); + } + return originalType; + } + function shouldNarrowTypeByTypePredicate(signature: Signature, expr: CallExpression): boolean { if (!signature.typePredicate) { return false; @@ -5670,18 +5683,16 @@ module ts { } let signature = getResolvedSignature(expr); if (!assumeTrue) { - if (type.flags & TypeFlags.Union && signature.typePredicate) { + if (type.flags & TypeFlags.Union && + signature.typePredicate && + getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); } return type; } if (shouldNarrowTypeByTypePredicate(signature, expr)) { - if (isTypeSubtypeOf(signature.typePredicate.type, type)) { - return signature.typePredicate.type; - } - if (type.flags & TypeFlags.Union) { - return getUnionType(filter((type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type))); - } + return getOptionalNarrowedType(type, signature.typePredicate.type); } return type; } @@ -8640,7 +8651,7 @@ module ts { getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), node.typePredicate.type); } - else if(node.typePredicate.parameterName) { + else if (node.typePredicate.parameterName) { error(node.typePredicate.parameterName, Diagnostics.Cannot_find_parameter_0, node.typePredicate.parameterName.text); @@ -10217,6 +10228,9 @@ module ts { if (node.expression) { let func = getContainingFunction(node); if (func) { + let signature = getSignatureFromDeclaration(func); + let exprType = checkExpressionCached(node.expression); + if (func.asteriskToken) { // A generator does not need its return expressions checked against its return type. // Instead, the yield expressions are checked against the element type. @@ -10225,13 +10239,7 @@ module ts { return; } - let signature = getSignatureFromDeclaration(func); - let exprType = checkExpressionCached(node.expression); - if (signature.typePredicate && exprType !== booleanType) { - error(node.expression, Diagnostics.A_type_guard_function_can_only_return_a_boolean); - } let returnType = getReturnTypeOfSignature(signature); - if (func.kind === SyntaxKind.SetAccessor) { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } @@ -10240,7 +10248,7 @@ module ts { error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } - else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) { + else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) { checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index aba138b9a1b..46c1cd37b3f 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -182,8 +182,8 @@ module ts { A_non_type_guard_function_is_not_assignable_to_a_type_guard_function: { code: 1224, category: DiagnosticCategory.Error, key: "A non-type guard function is not assignable to a type guard function." }, A_type_guard_function_can_only_return_a_boolean: { code: 1225, category: DiagnosticCategory.Error, key: "A type-guard function can only return a boolean." }, Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, - Type_guard_annotation_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type-guard annotation '{0}' is not assignable to '{1}'." }, - Parameter_index_from_0_does_not_match_the_parameter_index_from_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter index from '{0}' does not match the parameter index from '{1}'." }, + Type_predicate_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, + Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, Type_0_and_type_1_are_disjoint_types: { code: 1229, category: DiagnosticCategory.Error, key: "Type '{0}' and type '{1}' are disjoint types." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a94839fba7d..ebcba6386ff 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -715,11 +715,11 @@ "category": "Error", "code": 1226 }, - "Type-guard annotation '{0}' is not assignable to '{1}'.": { + "Type predicate '{0}' is not assignable to '{1}'.": { "category": "Error", "code": 1227 }, - "Parameter index from '{0}' does not match the parameter index from '{1}'.": { + "Parameter '{0}' is not in the same position as parameter '{1}'.": { "category": "Error", "code": 1228 }, diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 8b5ed551dff..001fe8a14ae 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS1225: A type-guard function can only return a boolean. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. @@ -17,13 +17,13 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(56,7): tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(61,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(66,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(71,46): error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. - Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. + Type predicate 'p1 is C' is not assignable to 'p1 is B'. Type 'C' is not assignable to type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. A non-type guard function is not assignable to a type guard function. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. - Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. - Parameter index from 'p2' does not match the parameter index from 'p1'. + Type predicate 'p2 is A' is not assignable to 'p1 is A'. + Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1226: Cannot find parameter 'p1'. @@ -45,7 +45,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) function hasANonBooleanReturnStatement(x): x is A { return ''; ~~ -!!! error TS1225: A type-guard function can only return a boolean. +!!! error TS2322: Type 'string' is not assignable to type 'boolean'. } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { @@ -137,7 +137,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) acceptingDifferentSignatureTypeGuardFunction(isC); ~~~ !!! error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. -!!! error TS2345: Type-guard annotation 'p1 is C' is not assignable to 'p1 is B'. +!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is B'. !!! error TS2345: Type 'C' is not assignable to type 'B'. // Boolean not assignable to type guard @@ -154,8 +154,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) assign2 = function(p1, p2): p2 is A { ~~~~~~~ !!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -!!! error TS2322: Type-guard annotation 'p2 is A' is not assignable to 'p1 is A'. -!!! error TS2322: Parameter index from 'p2' does not match the parameter index from 'p1'. +!!! error TS2322: Type predicate 'p2 is A' is not assignable to 'p1 is A'. +!!! error TS2322: Parameter 'p2' is not in the same position as parameter 'p1'. return true; }; From 3aa0839d1ba9a510dccd8ea7cf65501aae18dd43 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Wed, 3 Jun 2015 17:11:11 +0800 Subject: [PATCH 07/40] Fixes rebase issues --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80477ea1841..c75ba19df2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3267,7 +3267,7 @@ module ts { } links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, - minArgumentCount, hasRestParameters(declaration), hasStringLiterals); + minArgumentCount, hasRestParameter(declaration), hasStringLiterals); } return links.resolvedSignature; } From 1e39130f41a702e3f8ff53d939c87115bb53c5d8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jun 2015 06:57:20 -0700 Subject: [PATCH 08/40] Unified logic for renamed block scoped locals and other generated names --- src/compiler/checker.ts | 47 ++++++++-- src/compiler/emitter.ts | 195 ++++++++++++++-------------------------- src/compiler/types.ts | 6 +- 3 files changed, 112 insertions(+), 136 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6257031afbd..78dbe9077c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11821,6 +11821,38 @@ module ts { } } + function isStatementWithLocals(node: Node) { + switch (node.kind) { + case SyntaxKind.Block: + case SyntaxKind.CaseBlock: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + return true; + } + return false; + } + + function getIsNestedRedeclaration(symbol: Symbol): boolean { + let links = getSymbolLinks(symbol); + if (links.isNestedRedeclaration === undefined) { + let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); + links.isNestedRedeclaration = isStatementWithLocals(container) && + !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + return links.isNestedRedeclaration; + } + + function getReferencedNestedRedeclaration(node: Identifier): Declaration { + let symbol = getReferencedValueSymbol(node); + return symbol && symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol) ? symbol.valueDeclaration : undefined; + } + + function isNestedRedeclaration(node: Declaration): boolean { + let symbol = getSymbolOfNode(node); + return symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol); + } + function isValueAliasDeclaration(node: Node): boolean { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: @@ -11924,8 +11956,10 @@ module ts { /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the __metadata decorator. */ function serializeEntityName(node: EntityName, getGeneratedNameForNode: (Node: Node) => string, fallbackPath?: string[]): string { if (node.kind === SyntaxKind.Identifier) { - var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); - var text = substitution || (node).text; + // TODO(andersh): Fix this + // var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); + // var text = substitution || (node).text; + var text = (node).text; if (fallbackPath) { fallbackPath.push(text); } @@ -12140,11 +12174,6 @@ module ts { return hasProperty(globals, name); } - function resolvesToSomeValue(location: Node, name: string): boolean { - Debug.assert(!nodeIsSynthesized(location), "resolvesToSomeValue called with a synthesized location"); - return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - } - function getReferencedValueSymbol(reference: Identifier): Symbol { return getNodeLinks(reference).resolvedSymbol || resolveName(reference, reference.text, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, @@ -12198,9 +12227,10 @@ module ts { function createResolver(): EmitResolver { return { - getExpressionNameSubstitution, getReferencedExportContainer, getReferencedImportDeclaration, + getReferencedNestedRedeclaration, + isNestedRedeclaration, isValueAliasDeclaration, hasGlobalName, isReferencedAliasDeclaration, @@ -12214,7 +12244,6 @@ module ts { isSymbolAccessible, isEntityNameVisible, getConstantValue, - resolvesToSomeValue, collectLinkedAliases, getBlockScopedVariableId, getReferencedValueDeclaration, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2414c88a7a9..96dec48d82c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -125,7 +125,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { let generatedNameSet: Map = {}; let nodeToGeneratedName: string[] = []; - let blockScopedVariableToGeneratedName: string[]; let computedPropertyNamesToGeneratedNames: string[]; let extendsEmitted = false; @@ -268,6 +267,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function generateNameForNode(node: Node) { switch (node.kind) { + case SyntaxKind.Identifier: + return makeUniqueName((node).text); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: return generateNameForModuleOrEnum(node); @@ -648,19 +649,19 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { sourceMapDir = getDirectoryPath(normalizePath(jsFilePath)); } - function emitNodeWithSourceMap(node: Node, allowGeneratedIdentifiers?: boolean) { + function emitNodeWithSourceMap(node: Node) { if (node) { if (nodeIsSynthesized(node)) { - return emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + return emitNodeWithoutSourceMap(node); } if (node.kind != SyntaxKind.SourceFile) { recordEmitNodeStartSpan(node); - emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers); + emitNodeWithoutSourceMap(node); recordEmitNodeEndSpan(node); } else { recordNewSourceFileStart(node); - emitNodeWithoutSourceMap(node, /*allowGeneratedIdentifiers*/ false); + emitNodeWithoutSourceMap(node); } } } @@ -1187,6 +1188,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.ReturnStatement: + case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.SpreadElementExpression: case SyntaxKind.SwitchStatement: case SyntaxKind.TaggedTemplateExpression: @@ -1235,52 +1237,54 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else if (languageVersion < ScriptTarget.ES6) { - let declaration = resolver.getReferencedImportDeclaration(node); - if (declaration) { - if (declaration.kind === SyntaxKind.ImportClause) { + let alias = resolver.getReferencedImportDeclaration(node); + if (alias) { + if (alias.kind === SyntaxKind.ImportClause) { // Identifier references default import - write(getGeneratedNameForNode(declaration.parent)); + write(getGeneratedNameForNode(alias.parent)); write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); } else { // Identifier references named import - write(getGeneratedNameForNode(declaration.parent.parent.parent)); + write(getGeneratedNameForNode(alias.parent.parent.parent)); write("."); - writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + writeTextOfNode(currentSourceFile, (alias).propertyName || (alias).name); } return; } + let local = resolver.getReferencedNestedRedeclaration(node); + if (local) { + write(getGeneratedNameForNode(local.name)); + return; + } } writeTextOfNode(currentSourceFile, node); } - function getGeneratedNameForIdentifier(node: Identifier): string { - if (nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) { - return undefined; - } - - var variableId = resolver.getBlockScopedVariableId(node) - if (variableId === undefined) { - return undefined; - } - - return blockScopedVariableToGeneratedName[variableId]; - } - - function emitIdentifier(node: Identifier, allowGeneratedIdentifiers: boolean) { - if (allowGeneratedIdentifiers) { - let generatedName = getGeneratedNameForIdentifier(node); - if (generatedName) { - write(generatedName); - return; + function isNameOfNestedRedeclaration(node: Identifier) { + if (languageVersion < ScriptTarget.ES6) { + let parent = node.parent; + switch (parent.kind) { + case SyntaxKind.BindingElement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).name === node && resolver.isNestedRedeclaration(parent); } } + return false; + } + + function emitIdentifier(node: Identifier) { if (!node.parent) { write(node.text); } else if (isExpressionIdentifier(node)) { emitExpressionIdentifier(node); } + else if (isNameOfNestedRedeclaration(node)) { + write(getGeneratedNameForNode(node)); + } else { writeTextOfNode(currentSourceFile, node); } @@ -1326,7 +1330,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function emitBindingElement(node: BindingElement) { if (node.propertyName) { - emit(node.propertyName, /*allowGeneratedIdentifiers*/ false); + emit(node.propertyName); write(": "); } if (node.dotDotDotToken) { @@ -1679,7 +1683,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write("*"); } - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); if (languageVersion < ScriptTarget.ES6) { write(": function "); } @@ -1687,43 +1691,34 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } function emitPropertyAssignment(node: PropertyDeclaration) { - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); write(": "); emit(node.initializer); } + // Return true if identifier resolves to an exported member of a namespace + function isNamespaceExportReference(node: Identifier) { + let container = resolver.getReferencedExportContainer(node); + return container && container.kind !== SyntaxKind.SourceFile; + } + function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { - emit(node.name, /*allowGeneratedIdentifiers*/ false); - // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: - // module m { - // export let y; - // } - // module m { - // export let obj = { y }; - // } - // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version - if (languageVersion < ScriptTarget.ES6) { + // The name property of a short-hand property assignment is considered an expression position, so here + // we manually emit the identifier to avoid rewriting. + writeTextOfNode(currentSourceFile, node.name); + // If emitting pre-ES6 code, or if the name requires rewriting when resolved as an expression identifier, + // we emit a normal property assignment. For example: + // module m { + // export let y; + // } + // module m { + // let obj = { y }; + // } + // Here we need to emit obj = { y : m.y } regardless of the output target. + if (languageVersion < ScriptTarget.ES6 || isNamespaceExportReference(node.name)) { // Emit identifier as an identifier write(": "); - var generatedName = getGeneratedNameForIdentifier(node.name); - if (generatedName) { - write(generatedName); - } - else { - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); - } - } - else { - let container = resolver.getReferencedExportContainer(node.name); - if (container && container.kind !== SyntaxKind.SourceFile) { - // Emit identifier as an identifier - write(": "); - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); - } + emit(node.name); } } @@ -1776,7 +1771,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { let indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken); write("."); let indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name); - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); decreaseIndentIf(indentedBeforeDot, indentedAfterDot); } @@ -2778,8 +2773,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write(", "); } - renameNonTopLevelLetAndConst(name); - const isVariableDeclarationOrBindingElement = name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement); @@ -2847,11 +2840,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { - if (propName.kind !== SyntaxKind.Identifier) { - return createElementAccessExpression(object, propName); + let syntheticName = createSynthesizedNode(propName.kind); + syntheticName.text = propName.text; + if (syntheticName.kind !== SyntaxKind.Identifier) { + return createElementAccessExpression(object, syntheticName); } - - return createPropertyAccessExpression(object, propName); + return createPropertyAccessExpression(object, syntheticName); } function createSliceCall(value: Expression, sliceIndex: number): CallExpression { @@ -2873,8 +2867,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } for (let p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - // TODO(andersh): Computed property support - let propName = ((p).name); + let propName = (p).name; emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); } } @@ -2988,8 +2981,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else { - renameNonTopLevelLetAndConst(node.name); - let initializer = node.initializer; if (!initializer && languageVersion < ScriptTarget.ES6) { @@ -3049,54 +3040,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return getCombinedNodeFlags(node.parent); } - function renameNonTopLevelLetAndConst(node: Node): void { - // do not rename if - // - language version is ES6+ - // - node is synthesized - // - node is not identifier (can happen when tree is malformed) - // - node is definitely not name of variable declaration. - // it still can be part of parameter declaration, this check will be done next - if (languageVersion >= ScriptTarget.ES6 || - nodeIsSynthesized(node) || - node.kind !== SyntaxKind.Identifier || - (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { - return; - } - - let combinedFlags = getCombinedFlagsForIdentifier(node); - if (((combinedFlags & NodeFlags.BlockScoped) === 0) || combinedFlags & NodeFlags.Export) { - // do not rename exported or non-block scoped variables - return; - } - - // here it is known that node is a block scoped variable - let list = getAncestor(node, SyntaxKind.VariableDeclarationList); - if (list.parent.kind === SyntaxKind.VariableStatement) { - let isSourceFileLevelBinding = list.parent.parent.kind === SyntaxKind.SourceFile; - let isModuleLevelBinding = list.parent.parent.kind === SyntaxKind.ModuleBlock; - let isFunctionLevelBinding = - list.parent.parent.kind === SyntaxKind.Block && isFunctionLike(list.parent.parent.parent); - if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) { - return; - } - } - - let blockScopeContainer = getEnclosingBlockScopeContainer(node); - let parent = blockScopeContainer.kind === SyntaxKind.SourceFile - ? blockScopeContainer - : blockScopeContainer.parent; - - if (resolver.resolvesToSomeValue(parent, (node).text)) { - let variableId = resolver.getBlockScopedVariableId(node); - if (!blockScopedVariableToGeneratedName) { - blockScopedVariableToGeneratedName = []; - } - - let generatedName = makeUniqueName((node).text); - blockScopedVariableToGeneratedName[variableId] = generatedName; - } - } - function isES6ExportedDeclaration(node: Node) { return !!(node.flags & NodeFlags.Export) && languageVersion >= ScriptTarget.ES6 && @@ -3260,7 +3203,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function emitAccessor(node: AccessorDeclaration) { write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); - emit(node.name, /*allowGeneratedIdentifiers*/ false); + emit(node.name); emitSignatureAndBody(node); } @@ -5786,7 +5729,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitLeadingComments(node.endOfFileToken); } - function emitNodeWithoutSourceMap(node: Node, allowGeneratedIdentifiers?: boolean): void { + function emitNodeWithoutSourceMap(node: Node): void { if (!node) { return; } @@ -5800,7 +5743,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitLeadingComments(node); } - emitJavaScriptWorker(node, allowGeneratedIdentifiers); + emitJavaScriptWorker(node); if (emitComments) { emitTrailingComments(node); @@ -5850,11 +5793,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return true; } - function emitJavaScriptWorker(node: Node, allowGeneratedIdentifiers: boolean = true) { + function emitJavaScriptWorker(node: Node) { // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: - return emitIdentifier(node, allowGeneratedIdentifiers); + return emitIdentifier(node); case SyntaxKind.Parameter: return emitParameter(node); case SyntaxKind.MethodDeclaration: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e64d6afad8e..a8478a82797 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1398,6 +1398,8 @@ module ts { hasGlobalName(name: string): boolean; getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; + getReferencedNestedRedeclaration(node: Identifier): Declaration; + isNestedRedeclaration(node: Declaration): boolean; isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; @@ -1412,7 +1414,6 @@ module ts { isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; - resolvesToSomeValue(location: Node, name: string): boolean; getBlockScopedVariableId(node: Identifier): number; getReferencedValueDeclaration(reference: Identifier): Declaration; serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; @@ -1494,6 +1495,8 @@ module ts { HasExports = Class | Enum | Module, HasMembers = Class | Interface | TypeLiteral | ObjectLiteral, + BlockScoped = BlockScopedVariable | Class | Enum, + IsContainer = HasLocals | HasExports | HasMembers, PropertyOrAccessor = Property | Accessor, Export = ExportNamespace | ExportType | ExportValue, @@ -1523,6 +1526,7 @@ module ts { unionType?: UnionType; // Containing union type for union 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 } /* @internal */ From 334b22452a038725bad262c64fedea725eeefc41 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jun 2015 10:59:14 -0700 Subject: [PATCH 09/40] Moving logic around in getReferencedImportDeclaration --- src/compiler/checker.ts | 39 ++++++++++++++++++++------------------- src/compiler/emitter.ts | 23 ++++++++++++----------- src/compiler/types.ts | 2 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78dbe9077c6..85bb37c135e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11809,16 +11809,11 @@ module ts { } } - // When resolved as an expression identifier, if the given node references a default import or a named import, return - // the declaration node of that import. Otherwise, return undefined. - function getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier { + // When resolved as an expression identifier, if the given node references an import, return the declaration of + // that import. Otherwise, return undefined. + function getReferencedImportDeclaration(node: Identifier): Declaration { let symbol = getReferencedValueSymbol(node); - if (symbol && symbol.flags & SymbolFlags.Alias) { - let declaration = getDeclarationOfAliasSymbol(symbol); - if (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier) { - return declaration; - } - } + return symbol && symbol.flags & SymbolFlags.Alias ? getDeclarationOfAliasSymbol(symbol) : undefined; } function isStatementWithLocals(node: Node) { @@ -11833,24 +11828,30 @@ module ts { return false; } - function getIsNestedRedeclaration(symbol: Symbol): boolean { - let links = getSymbolLinks(symbol); - if (links.isNestedRedeclaration === undefined) { - let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); - links.isNestedRedeclaration = isStatementWithLocals(container) && - !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + function isNestedRedeclarationSymbol(symbol: Symbol): boolean { + if (symbol.flags & SymbolFlags.BlockScoped) { + let links = getSymbolLinks(symbol); + if (links.isNestedRedeclaration === undefined) { + let container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); + links.isNestedRedeclaration = isStatementWithLocals(container) && + !!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + return links.isNestedRedeclaration; } - return links.isNestedRedeclaration; + return false; } + // When resolved as an expression identifier, if the given node references a nested block scoped entity with + // a name that hides an existing name, return the declaration of that entity. Otherwise, return undefined. function getReferencedNestedRedeclaration(node: Identifier): Declaration { let symbol = getReferencedValueSymbol(node); - return symbol && symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol) ? symbol.valueDeclaration : undefined; + return symbol && isNestedRedeclarationSymbol(symbol) ? symbol.valueDeclaration : undefined; } + // Return true if the given node is a declaration of a nested block scoped entity with a name that hides an + // existing name. function isNestedRedeclaration(node: Declaration): boolean { - let symbol = getSymbolOfNode(node); - return symbol.flags & SymbolFlags.BlockScoped && getIsNestedRedeclaration(symbol); + return isNestedRedeclarationSymbol(getSymbolOfNode(node)); } function isValueAliasDeclaration(node: Node): boolean { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 96dec48d82c..6a68c6b0e85 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1237,24 +1237,25 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } else if (languageVersion < ScriptTarget.ES6) { - let alias = resolver.getReferencedImportDeclaration(node); - if (alias) { - if (alias.kind === SyntaxKind.ImportClause) { + let declaration = resolver.getReferencedImportDeclaration(node); + if (declaration) { + if (declaration.kind === SyntaxKind.ImportClause) { // Identifier references default import - write(getGeneratedNameForNode(alias.parent)); + write(getGeneratedNameForNode(declaration.parent)); write(languageVersion === ScriptTarget.ES3 ? '["default"]' : ".default"); + return; } - else { + else if (declaration.kind === SyntaxKind.ImportSpecifier) { // Identifier references named import - write(getGeneratedNameForNode(alias.parent.parent.parent)); + write(getGeneratedNameForNode(declaration.parent.parent.parent)); write("."); - writeTextOfNode(currentSourceFile, (alias).propertyName || (alias).name); + writeTextOfNode(currentSourceFile, (declaration).propertyName || (declaration).name); + return; } - return; } - let local = resolver.getReferencedNestedRedeclaration(node); - if (local) { - write(getGeneratedNameForNode(local.name)); + declaration = resolver.getReferencedNestedRedeclaration(node); + if (declaration) { + write(getGeneratedNameForNode(declaration.name)); return; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a8478a82797..205e1034448 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1397,7 +1397,7 @@ module ts { export interface EmitResolver { hasGlobalName(name: string): boolean; getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration; - getReferencedImportDeclaration(node: Identifier): ImportClause | ImportSpecifier; + getReferencedImportDeclaration(node: Identifier): Declaration; getReferencedNestedRedeclaration(node: Identifier): Declaration; isNestedRedeclaration(node: Declaration): boolean; isValueAliasDeclaration(node: Node): boolean; From 19e725636e25c6a42c3d729f917b6052053d2f2f Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 19:23:07 +0800 Subject: [PATCH 10/40] Adds PR feedback and removed references to typeguard (class) methods --- src/compiler/checker.ts | 104 +++++++------ .../diagnosticInformationMap.generated.ts | 11 +- src/compiler/diagnosticMessages.json | 14 +- src/compiler/parser.ts | 31 ++-- src/compiler/types.ts | 8 +- .../typeGuardFunctionErrors.errors.txt | 32 ++-- .../reference/typeGuardFunctionErrors.js | 4 +- .../reference/typeGuardMethods.errors.txt | 73 --------- tests/baselines/reference/typeGuardMethods.js | 141 ------------------ .../typeGuards/typeGuardMethods.ts | 64 -------- 10 files changed, 96 insertions(+), 386 deletions(-) delete mode 100644 tests/baselines/reference/typeGuardMethods.errors.txt delete mode 100644 tests/baselines/reference/typeGuardMethods.js delete mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c75ba19df2f..a6ff7bfc51c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1358,14 +1358,23 @@ module ts { return result; } - - function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + + function getWriteResult(data: T, enclosingDeclaration: Node, flags: TypeFormatFlags, method: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) => void) { let writer = getSingleLineStringWriter(); - getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); - + method(data, writer, enclosingDeclaration, flags); let result = writer.string(); releaseStringWriter(writer); + + return result; + } + + function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + let result = getWriteResult(signature, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildSignatureDisplay); + return result; + } + function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + let result = getWriteResult(type, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildTypeDisplay); let maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; if (maxLength && result.length >= maxLength) { result = result.substr(0, maxLength - "...".length) + "..."; @@ -3234,20 +3243,13 @@ module ts { if (classType) { returnType = classType; } - else if (declaration.typePredicate) { + else if (declaration.type && declaration.type.kind === SyntaxKind.TypePredicate) { returnType = booleanType; - let typePredicateNode = declaration.typePredicate; - let links = getNodeLinks(typePredicateNode); - if (links.typePredicateParameterIndex === undefined) { - links.typePredicateParameterIndex = getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName); - } - if (!links.typeFromTypePredicate) { - links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type); - } + let typePredicateNode = declaration.type; typePredicate = { parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, - parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined, - type: links.typeFromTypePredicate + parameterIndex: typePredicateNode.parameterName ? getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName) : undefined, + type: getTypeFromTypeNode(typePredicateNode.type) }; } else if (declaration.type) { @@ -4662,8 +4664,8 @@ module ts { if (source.typePredicate && target.typePredicate) { let hasDifferentParamaterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex; - let hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type); - if (hasDifferentParamaterIndex || hasDifferentTypes) { + let hasDifferentTypes: boolean; + if (hasDifferentParamaterIndex || (hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type))) { if (reportErrors) { let sourceParamText = source.typePredicate.parameterName; let targetParamText = target.typePredicate.parameterName; @@ -4675,7 +4677,7 @@ module ts { sourceParamText, targetParamText); } - if (hasDifferentTypes) { + else if (hasDifferentTypes) { reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, sourceTypeText, targetTypeText); @@ -4687,11 +4689,10 @@ module ts { } return Ternary.False; } - return Ternary.True; } else if (!source.typePredicate && target.typePredicate) { if (reportErrors) { - reportError(Diagnostics.A_non_type_guard_function_is_not_assignable_to_a_type_guard_function); + reportError(Diagnostics.Signature_0_must_have_a_type_predicate, signatureToString(source)); } return Ternary.False; } @@ -5231,12 +5232,12 @@ module ts { if (source.typePredicate && target.typePredicate) { if (target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { // Return types from type predicates are treated as booleans. In order to infer types - // from type predicates we would need infer from the type from type predicates. Since - // we can't infer any type information from the return types. We can just add a return - // statement after the below infer statement. + // from type predicates we would need to infer from the type of type predicates. Since + // we can't infer any type information from the return types — we can just add a return + // statement after the below infer type statement. inferFromTypes(source.typePredicate.type, target.typePredicate.type); - return; } + return; } inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } @@ -8635,37 +8636,28 @@ module ts { forEach(node.parameters, checkParameter); if (node.type) { - checkSourceElement(node.type); - } - - if (node.typePredicate) { - let links = getNodeLinks(node.typePredicate); - if (links.typePredicateParameterIndex === undefined) { - links.typePredicateParameterIndex = getTypePredicateParameterIndex(node.parameters, node.typePredicate.parameterName); - } - if (!links.typeFromTypePredicate) { - links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type); - } - if (links.typePredicateParameterIndex >= 0) { - checkTypeAssignableTo(links.typeFromTypePredicate, - getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]), - node.typePredicate.type); - } - else if (node.typePredicate.parameterName) { - error(node.typePredicate.parameterName, - Diagnostics.Cannot_find_parameter_0, - node.typePredicate.parameterName.text); + if (node.type.kind === SyntaxKind.TypePredicate) { + let typePredicate = getSignatureFromDeclaration(node).typePredicate; + if ((node.type).type.kind === SyntaxKind.TypePredicate) { + error((node.type).type, + Diagnostics.Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate, + getTextOfNode((node.type).type)); + } + else { + if (typePredicate.parameterIndex >= 0) { + checkTypeAssignableTo(typePredicate.type, + getTypeAtLocation(node.parameters[typePredicate.parameterIndex]), + (node.type).type); + } + else if ((node.type).parameterName) { + error((node.type).parameterName, + Diagnostics.Cannot_find_parameter_0, + typePredicate.parameterName); + } + } } else { - let typeOfClass = getTypeAtLocation(node.parent); - if (!isTypeSubtypeOf(links.typeFromTypePredicate, typeOfClass) && - !isTypeSubtypeOf(typeOfClass, links.typeFromTypePredicate)) { - - error(node.typePredicate, - Diagnostics.Type_0_and_type_1_are_disjoint_types, - typeToString(links.typeFromTypePredicate), - typeToString(typeOfClass)); - } + checkSourceElement(node.type); } } @@ -11300,6 +11292,10 @@ module ts { links.exportsChecked = true; } } + + function checkTypePredicateNode(node: TypePredicateNode) { + + } function checkSourceElement(node: Node): void { if (!node) return; @@ -11328,6 +11324,8 @@ module ts { return checkAccessorDeclaration(node); case SyntaxKind.TypeReference: return checkTypeReferenceNode(node); + case SyntaxKind.TypePredicate: + return checkTypePredicateNode(node); case SyntaxKind.TypeQuery: return checkTypeQuery(node); case SyntaxKind.TypeLiteral: diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 46c1cd37b3f..a949c5c034e 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -179,12 +179,11 @@ module ts { Generators_are_not_allowed_in_an_ambient_context: { code: 1221, category: DiagnosticCategory.Error, key: "Generators are not allowed in an ambient context." }, An_overload_signature_cannot_be_declared_as_a_generator: { code: 1222, category: DiagnosticCategory.Error, key: "An overload signature cannot be declared as a generator." }, _0_tag_already_specified: { code: 1223, category: DiagnosticCategory.Error, key: "'{0}' tag already specified." }, - A_non_type_guard_function_is_not_assignable_to_a_type_guard_function: { code: 1224, category: DiagnosticCategory.Error, key: "A non-type guard function is not assignable to a type guard function." }, - A_type_guard_function_can_only_return_a_boolean: { code: 1225, category: DiagnosticCategory.Error, key: "A type-guard function can only return a boolean." }, - Cannot_find_parameter_0: { code: 1226, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, - Type_predicate_0_is_not_assignable_to_1: { code: 1227, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, - Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1228, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Type_0_and_type_1_are_disjoint_types: { code: 1229, category: DiagnosticCategory.Error, key: "Type '{0}' and type '{1}' are disjoint types." }, + Signature_0_must_have_a_type_predicate: { code: 1224, category: DiagnosticCategory.Error, key: "Signature '{0}' must have a type predicate." }, + Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, + Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, + Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, + Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate: { code: 1228, category: DiagnosticCategory.Error, key: "Cannot define type predicate '{0}' as a type to a type predicate." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ebcba6386ff..a3e4e8c6e52 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -703,30 +703,26 @@ "category": "Error", "code": 1223 }, - "A non-type guard function is not assignable to a type guard function.": { + "Signature '{0}' must have a type predicate.": { "category": "Error", "code": 1224 }, - "A type-guard function can only return a boolean.": { + "Cannot find parameter '{0}'.": { "category": "Error", "code": 1225 }, - "Cannot find parameter '{0}'.": { + "Type predicate '{0}' is not assignable to '{1}'.": { "category": "Error", "code": 1226 }, - "Type predicate '{0}' is not assignable to '{1}'.": { + "Parameter '{0}' is not in the same position as parameter '{1}'.": { "category": "Error", "code": 1227 }, - "Parameter '{0}' is not in the same position as parameter '{1}'.": { + "Cannot define type predicate '{0}' as a type to a type predicate.": { "category": "Error", "code": 1228 }, - "Type '{0}' and type '{1}' are disjoint types.": { - "category": "Error", - "code": 1229 - }, "Duplicate identifier '{0}'.": { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0f84ec20383..818e626b5a8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -81,8 +81,7 @@ module ts { visitNodes(cbNodes, node.modifiers) || visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).typePredicate); + visitNode(cbNode, (node).type); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: @@ -99,7 +98,6 @@ module ts { visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).typePredicate) || visitNode(cbNode, (node).equalsGreaterThanToken) || visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: @@ -768,7 +766,7 @@ module ts { return (contextFlags & ParserContextFlags.Decorator) !== 0; } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any) { + function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { let start = scanner.getTokenPos(); let length = scanner.getTextPos() - start; @@ -2053,13 +2051,10 @@ module ts { if (returnTokenRequired) { parseExpected(returnToken); - parseTypePredicateOrReturnType(signature); + signature.type = parseType(); } else if (parseOptional(returnToken)) { - parseTypePredicateOrReturnType(signature); - } - if (token === SyntaxKind.IsKeyword) { - parseTypePredicate(signature); + signature.type = parseType(); } } @@ -2497,6 +2492,22 @@ module ts { return result; } + + function parseTypePredicateOrHigher(): TypeNode { + let type = parseUnionTypeOrHigher(); + if (token === SyntaxKind.IsKeyword && + type.kind === SyntaxKind.TypeReference && + (type).typeName.kind === SyntaxKind.Identifier) { + + nextToken(); + + let typePredicate = createNode(SyntaxKind.TypePredicate, type.pos); + typePredicate.parameterName = (type).typeName; + typePredicate.type = parseType(); + return finishNode(typePredicate); + } + return type; + } function parseTypeWorker(): TypeNode { if (isStartOfFunctionType()) { @@ -2505,7 +2516,7 @@ module ts { if (token === SyntaxKind.NewKeyword) { return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); } - return parseUnionTypeOrHigher(); + return parseTypePredicateOrHigher(); } function parseTypeAnnotation(): TypeNode { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index acf71db16c7..afdfe651c67 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -608,9 +608,9 @@ module ts { typeName: EntityName; typeArguments?: NodeArray; } - + export interface TypePredicateNode extends TypeNode { - parameterName?: Identifier; + parameterName: Identifier; type: TypeNode; } @@ -1387,7 +1387,7 @@ module ts { export interface TypePredicate { parameterName: string; - parameterIndex?: number; + parameterIndex: number; type: Type; } @@ -1577,8 +1577,6 @@ module ts { assignmentChecks?: Map; // Cache of assignment checks hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context importOnRightSide?: Symbol; // for import declarations - import that appear on the right side - typePredicateParameterIndex?: number; // Index of type predicate parameter - typeFromTypePredicate?: Type; // Type from TypePredicate } export const enum TypeFlags { diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 001fe8a14ae..47479b221aa 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,14 +1,10 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,60): error TS1005: ';' expected. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,62): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(28,1): error TS1128: Declaration or statement expected. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,38): error TS1226: Cannot find parameter 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,38): error TS1225: Cannot find parameter 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(34,51): error TS2322: Type 'B' is not assignable to type 'A'. Property 'propA' is missing in type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(38,56): error TS2322: Type 'number' is not assignable to type 'string'. @@ -20,15 +16,15 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(71,46) Type predicate 'p1 is C' is not assignable to 'p1 is B'. Type 'C' is not assignable to type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. - A non-type guard function is not assignable to a type guard function. + Signature '(p1: any, p2: any): boolean' must have a type predicate. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1226: Cannot find parameter 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1225: Cannot find parameter 'p1'. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (22 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (18 errors) ==== class A { propA: number; @@ -49,16 +45,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { - ~ -!!! error TS2304: Cannot find name 'x'. - ~~ -!!! error TS1144: '{' or ';' expected. - ~~ -!!! error TS2304: Cannot find name 'is'. - ~ -!!! error TS1005: ';' expected. - ~ -!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate. return true; } @@ -80,7 +68,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) function hasNonMatchingParameter(y): x is A { ~ -!!! error TS1226: Cannot find parameter 'x'. +!!! error TS1225: Cannot find parameter 'x'. return true; } @@ -145,7 +133,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) assign1 = function(p1, p2): boolean { ~~~~~~~ !!! error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -!!! error TS2322: A non-type guard function is not assignable to a type guard function. +!!! error TS2322: Signature '(p1: any, p2: any): boolean' must have a type predicate. return true; }; @@ -170,5 +158,5 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) // Type guard paramater referring to a binding pattern declare function destructureParameter({ p1, p2, p3 }): p1 is A; ~~ -!!! error TS1226: Cannot find parameter 'p1'. +!!! error TS1225: Cannot find parameter 'p1'. \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index cc65fc00cba..84dd534f9d2 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -120,9 +120,7 @@ var C = (function (_super) { function hasANonBooleanReturnStatement(x) { return ''; } -is; -A; -{ +function hasTypeGuardTypeInsideTypeGuardType(x) { return true; } function hasMissingIsKeyword() { diff --git a/tests/baselines/reference/typeGuardMethods.errors.txt b/tests/baselines/reference/typeGuardMethods.errors.txt deleted file mode 100644 index 246f84ccc09..00000000000 --- a/tests/baselines/reference/typeGuardMethods.errors.txt +++ /dev/null @@ -1,73 +0,0 @@ -tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(14,12): error TS1229: Type 'A' and type 'B' are disjoint types. -tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts(17,12): error TS1229: Type 'C' and type 'B' are disjoint types. - - -==== tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts (2 errors) ==== - - class A { - propA: number; - isA(): this is A { - return true; - } - isC(): this is C { - return false; - } - } - - class B { - propB: number; - isA(): this is A { - ~~~~~~~~~ -!!! error TS1229: Type 'A' and type 'B' are disjoint types. - return false; - } - isC(): this is C { - ~~~~~~~~~ -!!! error TS1229: Type 'C' and type 'B' are disjoint types. - return false; - } - } - - class C extends A { - propC: number; - isA(): this is A { - return false; - } - isC(): this is C { - return true; - } - } - - class D extends C { - isA(): this is A { - return false; - } - isString(x: any): x is string { // with parameter declaration - return true; - } - } - - var a: A; - - // Basic. - if (a.isC()) { - a.propC; - } - - // Sub type. - var subType: C; - if(subType.isA()) { - subType.propC; - } - - // Union type. - var union: A | B; - if(union.isA()) { - union.propA; - } - - var b: any; - var d = new D; - if(d.isString(b)) { - b.length; - } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardMethods.js b/tests/baselines/reference/typeGuardMethods.js deleted file mode 100644 index dcc7eca43c9..00000000000 --- a/tests/baselines/reference/typeGuardMethods.js +++ /dev/null @@ -1,141 +0,0 @@ -//// [typeGuardMethods.ts] - -class A { - propA: number; - isA(): this is A { - return true; - } - isC(): this is C { - return false; - } -} - -class B { - propB: number; - isA(): this is A { - return false; - } - isC(): this is C { - return false; - } -} - -class C extends A { - propC: number; - isA(): this is A { - return false; - } - isC(): this is C { - return true; - } -} - -class D extends C { - isA(): this is A { - return false; - } - isString(x: any): x is string { // with parameter declaration - return true; - } -} - -var a: A; - -// Basic. -if (a.isC()) { - a.propC; -} - -// Sub type. -var subType: C; -if(subType.isA()) { - subType.propC; -} - -// Union type. -var union: A | B; -if(union.isA()) { - union.propA; -} - -var b: any; -var d = new D; -if(d.isString(b)) { - b.length; -} - -//// [typeGuardMethods.js] -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); -}; -var A = (function () { - function A() { - } - A.prototype.isA = function () { - return true; - }; - A.prototype.isC = function () { - return false; - }; - return A; -})(); -var B = (function () { - function B() { - } - B.prototype.isA = function () { - return false; - }; - B.prototype.isC = function () { - return false; - }; - return B; -})(); -var C = (function (_super) { - __extends(C, _super); - function C() { - _super.apply(this, arguments); - } - C.prototype.isA = function () { - return false; - }; - C.prototype.isC = function () { - return true; - }; - return C; -})(A); -var D = (function (_super) { - __extends(D, _super); - function D() { - _super.apply(this, arguments); - } - D.prototype.isA = function () { - return false; - }; - D.prototype.isString = function (x) { - return true; - }; - return D; -})(C); -var a; -// Basic. -if (a.isC()) { - a.propC; -} -// Sub type. -var subType; -if (subType.isA()) { - subType.propC; -} -// Union type. -var union; -if (union.isA()) { - union.propA; -} -var b; -var d = new D; -if (d.isString(b)) { - b.length; -} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts deleted file mode 100644 index 80ae65a7ddb..00000000000 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardMethods.ts +++ /dev/null @@ -1,64 +0,0 @@ - -class A { - propA: number; - isA(): this is A { - return true; - } - isC(): this is C { - return false; - } -} - -class B { - propB: number; - isA(): this is A { - return false; - } - isC(): this is C { - return false; - } -} - -class C extends A { - propC: number; - isA(): this is A { - return false; - } - isC(): this is C { - return true; - } -} - -class D extends C { - isA(): this is A { - return false; - } - isString(x: any): x is string { // with parameter declaration - return true; - } -} - -var a: A; - -// Basic. -if (a.isC()) { - a.propC; -} - -// Sub type. -var subType: C; -if(subType.isA()) { - subType.propC; -} - -// Union type. -var union: A | B; -if(union.isA()) { - union.propA; -} - -var b: any; -var d = new D; -if(d.isString(b)) { - b.length; -} \ No newline at end of file From e1f82c599b7d5e859fd189c933ded4aa8ae9e6e3 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 19:35:22 +0800 Subject: [PATCH 11/40] Removes old type predicate functions --- src/compiler/checker.ts | 15 ++------------- src/compiler/parser.ts | 28 ---------------------------- 2 files changed, 2 insertions(+), 41 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a6ff7bfc51c..1f5e9a5264f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1358,7 +1358,7 @@ module ts { return result; } - + function getWriteResult(data: T, enclosingDeclaration: Node, flags: TypeFormatFlags, method: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) => void) { let writer = getSingleLineStringWriter(); method(data, writer, enclosingDeclaration, flags); @@ -5670,11 +5670,6 @@ module ts { return true; } - if (expr.expression.kind === SyntaxKind.PropertyAccessExpression && - getSymbolAtLocation((expr.expression).expression) === symbol) { - - return true; - } return false; } @@ -10221,6 +10216,7 @@ module ts { let func = getContainingFunction(node); if (func) { let signature = getSignatureFromDeclaration(func); + let returnType = getReturnTypeOfSignature(signature); let exprType = checkExpressionCached(node.expression); if (func.asteriskToken) { @@ -10231,7 +10227,6 @@ module ts { return; } - let returnType = getReturnTypeOfSignature(signature); if (func.kind === SyntaxKind.SetAccessor) { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } @@ -11292,10 +11287,6 @@ module ts { links.exportsChecked = true; } } - - function checkTypePredicateNode(node: TypePredicateNode) { - - } function checkSourceElement(node: Node): void { if (!node) return; @@ -11324,8 +11315,6 @@ module ts { return checkAccessorDeclaration(node); case SyntaxKind.TypeReference: return checkTypeReferenceNode(node); - case SyntaxKind.TypePredicate: - return checkTypePredicateNode(node); case SyntaxKind.TypeQuery: return checkTypeQuery(node); case SyntaxKind.TypeLiteral: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 818e626b5a8..9a1ec116680 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2012,34 +2012,6 @@ module ts { return parseInitializer(/*inParameter*/ true); } - function parseTypePredicate(signature: SignatureDeclaration) { - let node = createNode(SyntaxKind.TypePredicate); - if (token !== SyntaxKind.ThisKeyword) { - node.pos = signature.type.pos; - node.parameterName = (signature.type).typeName; - signature.type = undefined; - } - else { - // Swallow `this` - nextToken(); - } - - // Swallow `is` - nextToken(); - - node.type = parseType(); - signature.typePredicate = finishNode(node); - } - - function parseTypePredicateOrReturnType(signature: SignatureDeclaration) { - if (token === SyntaxKind.ThisKeyword) { - parseTypePredicate(signature); - } - else { - signature.type = parseType(); - } - } - function fillSignature( returnToken: SyntaxKind, yieldAndGeneratorParameterContext: boolean, From f8dc6bb310ecb9cd5d3402f064c5fc81b799405c Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 20:16:48 +0800 Subject: [PATCH 12/40] Changed name from method to buildDisplay --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1f5e9a5264f..66898ebcbcd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1359,9 +1359,9 @@ module ts { return result; } - function getWriteResult(data: T, enclosingDeclaration: Node, flags: TypeFormatFlags, method: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) => void) { + function getWriteResult(data: T, enclosingDeclaration: Node, flags: TypeFormatFlags, buildDisplay: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) => void) { let writer = getSingleLineStringWriter(); - method(data, writer, enclosingDeclaration, flags); + buildDisplay(data, writer, enclosingDeclaration, flags); let result = writer.string(); releaseStringWriter(writer); From f3e6f5ba1f098496414857753894623a4ce73ffe Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 4 Jun 2015 07:16:06 -0700 Subject: [PATCH 13/40] Removing getGeneratedNameForNode from type serializers --- src/compiler/checker.ts | 41 +++++++++++++++++++++-------------------- src/compiler/emitter.ts | 6 +++--- src/compiler/types.ts | 6 +++--- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85bb37c135e..1076fac90b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11955,9 +11955,10 @@ module ts { } /** Serializes an EntityName (with substitutions) to an appropriate JS constructor value. Used by the __metadata decorator. */ - function serializeEntityName(node: EntityName, getGeneratedNameForNode: (Node: Node) => string, fallbackPath?: string[]): string { + function serializeEntityName(node: EntityName, fallbackPath?: string[]): string { if (node.kind === SyntaxKind.Identifier) { - // TODO(andersh): Fix this + // TODO(ron.buckton): The getExpressionNameSubstitution function has been removed, but calling it + // here has no effect anyway as an identifier in a type name is not an expression. // var substitution = getExpressionNameSubstitution(node, getGeneratedNameForNode); // var text = substitution || (node).text; var text = (node).text; @@ -11969,8 +11970,8 @@ module ts { } } else { - var left = serializeEntityName((node).left, getGeneratedNameForNode, fallbackPath); - var right = serializeEntityName((node).right, getGeneratedNameForNode, fallbackPath); + var left = serializeEntityName((node).left, fallbackPath); + var right = serializeEntityName((node).right, fallbackPath); if (!fallbackPath) { return left + "." + right; } @@ -11978,7 +11979,7 @@ module ts { } /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */ - function serializeTypeReferenceNode(node: TypeReferenceNode, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + function serializeTypeReferenceNode(node: TypeReferenceNode): string | string[] { // serialization of a TypeReferenceNode uses the following rules: // // * The serialized type of a TypeReference that is `void` is "void 0". @@ -12011,11 +12012,11 @@ module ts { } else if (type === unknownType) { var fallbackPath: string[] = []; - serializeEntityName(node.typeName, getGeneratedNameForNode, fallbackPath); + serializeEntityName(node.typeName, fallbackPath); return fallbackPath; } else if (type.symbol && type.symbol.valueDeclaration) { - return serializeEntityName(node.typeName, getGeneratedNameForNode); + return serializeEntityName(node.typeName); } else if (typeHasCallOrConstructSignatures(type)) { return "Function"; @@ -12025,7 +12026,7 @@ module ts { } /** Serializes a TypeNode to an appropriate JS constructor value. Used by the __metadata decorator. */ - function serializeTypeNode(node: TypeNode | LiteralExpression, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + function serializeTypeNode(node: TypeNode | LiteralExpression): string | string[] { // serialization of a TypeNode uses the following rules: // // * The serialized type of `void` is "void 0" (undefined). @@ -12041,7 +12042,7 @@ module ts { case SyntaxKind.VoidKeyword: return "void 0"; case SyntaxKind.ParenthesizedType: - return serializeTypeNode((node).type, getGeneratedNameForNode); + return serializeTypeNode((node).type); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: return "Function"; @@ -12056,7 +12057,7 @@ module ts { case SyntaxKind.NumberKeyword: return "Number"; case SyntaxKind.TypeReference: - return serializeTypeReferenceNode(node, getGeneratedNameForNode); + return serializeTypeReferenceNode(node); case SyntaxKind.TypeQuery: case SyntaxKind.TypeLiteral: case SyntaxKind.UnionType: @@ -12072,7 +12073,7 @@ module ts { } /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the __metadata decorator for a class member. */ - function serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + function serializeTypeOfNode(node: Node): string | string[] { // serialization of the type of a declaration uses the following rules: // // * The serialized type of a ClassDeclaration is "Function" @@ -12085,10 +12086,10 @@ module ts { // For rules on serializing type annotations, see `serializeTypeNode`. switch (node.kind) { case SyntaxKind.ClassDeclaration: return "Function"; - case SyntaxKind.PropertyDeclaration: return serializeTypeNode((node).type, getGeneratedNameForNode); - case SyntaxKind.Parameter: return serializeTypeNode((node).type, getGeneratedNameForNode); - case SyntaxKind.GetAccessor: return serializeTypeNode((node).type, getGeneratedNameForNode); - case SyntaxKind.SetAccessor: return serializeTypeNode(getSetAccessorTypeAnnotationNode(node), getGeneratedNameForNode); + case SyntaxKind.PropertyDeclaration: return serializeTypeNode((node).type); + case SyntaxKind.Parameter: return serializeTypeNode((node).type); + case SyntaxKind.GetAccessor: return serializeTypeNode((node).type); + case SyntaxKind.SetAccessor: return serializeTypeNode(getSetAccessorTypeAnnotationNode(node)); } if (isFunctionLike(node)) { return "Function"; @@ -12097,7 +12098,7 @@ module ts { } /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */ - function serializeParameterTypesOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): (string | string[])[] { + function serializeParameterTypesOfNode(node: Node): (string | string[])[] { // serialization of parameter types uses the following rules: // // * If the declaration is a class, the parameters of the first constructor with a body are used. @@ -12130,10 +12131,10 @@ module ts { else { parameterType = undefined; } - result[i] = serializeTypeNode(parameterType, getGeneratedNameForNode); + result[i] = serializeTypeNode(parameterType); } else { - result[i] = serializeTypeOfNode(parameters[i], getGeneratedNameForNode); + result[i] = serializeTypeOfNode(parameters[i]); } } return result; @@ -12144,9 +12145,9 @@ module ts { } /** Serializes the return type of function. Used by the __metadata decorator for a method. */ - function serializeReturnTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[] { + function serializeReturnTypeOfNode(node: Node): string | string[] { if (node && isFunctionLike(node)) { - return serializeTypeNode((node).type, getGeneratedNameForNode); + return serializeTypeNode((node).type); } return "void 0"; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6a68c6b0e85..2ad3f3634ee 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4307,7 +4307,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { let argumentsWritten = 0; if (compilerOptions.emitDecoratorMetadata) { if (shouldEmitTypeMetadata(node)) { - var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode); + var serializedType = resolver.serializeTypeOfNode(node); if (serializedType) { if (writeComma) { write(", "); @@ -4320,7 +4320,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } if (shouldEmitParamTypesMetadata(node)) { - var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode); + var serializedTypes = resolver.serializeParameterTypesOfNode(node); if (serializedTypes) { if (writeComma || argumentsWritten) { write(", "); @@ -4338,7 +4338,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } } if (shouldEmitReturnTypeMetadata(node)) { - var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode); + var serializedType = resolver.serializeReturnTypeOfNode(node); if (serializedType) { if (writeComma || argumentsWritten) { write(", "); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 205e1034448..26736b69d8e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1416,9 +1416,9 @@ module ts { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; getBlockScopedVariableId(node: Identifier): number; getReferencedValueDeclaration(reference: Identifier): Declaration; - serializeTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; - serializeParameterTypesOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): (string | string[])[]; - serializeReturnTypeOfNode(node: Node, getGeneratedNameForNode: (Node: Node) => string): string | string[]; + serializeTypeOfNode(node: Node): string | string[]; + serializeParameterTypesOfNode(node: Node): (string | string[])[]; + serializeReturnTypeOfNode(node: Node): string | string[]; } export const enum SymbolFlags { From 76bc9be701fa71436a2f73419c0c6adb0585b0db Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 22:20:46 +0800 Subject: [PATCH 14/40] Refactor to-string functions --- src/compiler/checker.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 66898ebcbcd..46405f1f0f4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1349,28 +1349,20 @@ module ts { writer.writeSpace(" "); } - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { - let writer = getSingleLineStringWriter(); - getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning); - - let result = writer.string(); - releaseStringWriter(writer); - - return result; - } - - function getWriteResult(data: T, enclosingDeclaration: Node, flags: TypeFormatFlags, buildDisplay: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) => void) { + function getWriteResult(data: T, enclosingDeclaration: Node, flags: U, buildDisplay: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: U) => void): string { let writer = getSingleLineStringWriter(); buildDisplay(data, writer, enclosingDeclaration, flags); let result = writer.string(); releaseStringWriter(writer); - return result; } - + + function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { + return getWriteResult(symbol, enclosingDeclaration, meaning, getSymbolDisplayBuilder().buildSymbolDisplay); + } + function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - let result = getWriteResult(signature, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildSignatureDisplay); - return result; + return getWriteResult(signature, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildSignatureDisplay); } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { @@ -1379,7 +1371,6 @@ module ts { if (maxLength && result.length >= maxLength) { result = result.substr(0, maxLength - "...".length) + "..."; } - return result; } From 250bd0db4fb6a2c561ccdf5cb3026f8382ba0882 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 22:47:59 +0800 Subject: [PATCH 15/40] Change name from data to info --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 46405f1f0f4..178328ae198 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1349,9 +1349,9 @@ module ts { writer.writeSpace(" "); } - function getWriteResult(data: T, enclosingDeclaration: Node, flags: U, buildDisplay: (data: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: U) => void): string { + function getWriteResult(info: T, enclosingDeclaration: Node, flags: U, buildDisplay: (info: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: U) => void): string { let writer = getSingleLineStringWriter(); - buildDisplay(data, writer, enclosingDeclaration, flags); + buildDisplay(info, writer, enclosingDeclaration, flags); let result = writer.string(); releaseStringWriter(writer); return result; From 48acb489caeda3b2bf9bc3ebde147b93b0fdf3a3 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 22:51:31 +0800 Subject: [PATCH 16/40] Add back void annotation --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 178328ae198..0ba81bfa124 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2782,7 +2782,7 @@ module ts { return type; } - function resolveClassOrInterfaceMembers(type: InterfaceType) { + function resolveClassOrInterfaceMembers(type: InterfaceType): void { let target = resolveDeclaredMembers(type); let members = target.symbol.members; let callSignatures = target.declaredCallSignatures; From fc1bafdc578ac6ccdb0dc4f950436c95b9411288 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 4 Jun 2015 09:44:54 -0700 Subject: [PATCH 17/40] Accepting new baselines --- tests/baselines/reference/ES5For-of17.js | 2 +- tests/baselines/reference/ES5For-of20.js | 2 +- .../baselines/reference/classDeclarationBlockScoping1.js | 6 +++--- .../baselines/reference/classDeclarationBlockScoping2.js | 8 ++++---- tests/baselines/reference/exportsAndImports3-amd.js | 8 ++++---- tests/baselines/reference/exportsAndImports3.js | 8 ++++---- tests/baselines/reference/localTypes1.js | 8 ++++---- .../amd/testGlo.js | 4 ++-- .../node/testGlo.js | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/baselines/reference/ES5For-of17.js b/tests/baselines/reference/ES5For-of17.js index 50064d82932..fb3a02fd0e9 100644 --- a/tests/baselines/reference/ES5For-of17.js +++ b/tests/baselines/reference/ES5For-of17.js @@ -11,7 +11,7 @@ for (let v of []) { for (var _i = 0, _a = []; _i < _a.length; _i++) { var v = _a[_i]; v; - for (var _b = 0, _c = [v]; _b < _c.length; _b++) { + for (var _b = 0, _c = [v_1]; _b < _c.length; _b++) { var v_1 = _c[_b]; var x = v_1; v_1++; diff --git a/tests/baselines/reference/ES5For-of20.js b/tests/baselines/reference/ES5For-of20.js index c6376ab05d7..d21ab73f8b5 100644 --- a/tests/baselines/reference/ES5For-of20.js +++ b/tests/baselines/reference/ES5For-of20.js @@ -10,7 +10,7 @@ for (let v of []) { for (var _i = 0, _a = []; _i < _a.length; _i++) { var v = _a[_i]; var v_1; - for (var _b = 0, _c = [v]; _b < _c.length; _b++) { + for (var _b = 0, _c = [v_2]; _b < _c.length; _b++) { var v_2 = _c[_b]; var v_3; } diff --git a/tests/baselines/reference/classDeclarationBlockScoping1.js b/tests/baselines/reference/classDeclarationBlockScoping1.js index 717c2f788c3..4c7f9d8e24a 100644 --- a/tests/baselines/reference/classDeclarationBlockScoping1.js +++ b/tests/baselines/reference/classDeclarationBlockScoping1.js @@ -14,9 +14,9 @@ var C = (function () { return C; })(); { - var C = (function () { - function C() { + var C_1 = (function () { + function C_1() { } - return C; + return C_1; })(); } diff --git a/tests/baselines/reference/classDeclarationBlockScoping2.js b/tests/baselines/reference/classDeclarationBlockScoping2.js index 9e468077119..57001d0d287 100644 --- a/tests/baselines/reference/classDeclarationBlockScoping2.js +++ b/tests/baselines/reference/classDeclarationBlockScoping2.js @@ -18,12 +18,12 @@ function f() { })(); var c1 = C; { - var C = (function () { - function C() { + var C_1 = (function () { + function C_1() { } - return C; + return C_1; })(); - var c2 = C; + var c2 = C_1; } return C === c1; } diff --git a/tests/baselines/reference/exportsAndImports3-amd.js b/tests/baselines/reference/exportsAndImports3-amd.js index e816dec9f62..3a33b12c7ff 100644 --- a/tests/baselines/reference/exportsAndImports3-amd.js +++ b/tests/baselines/reference/exportsAndImports3-amd.js @@ -40,25 +40,25 @@ define(["require", "exports"], function (require, exports) { exports.v1 = exports.v; function f() { } exports.f = f; - exports.f1 = exports.f; + exports.f1 = f; var C = (function () { function C() { } return C; })(); exports.C = C; - exports.C1 = exports.C; + exports.C1 = C; (function (E) { E[E["A"] = 0] = "A"; E[E["B"] = 1] = "B"; E[E["C"] = 2] = "C"; })(exports.E || (exports.E = {})); var E = exports.E; - exports.E1 = exports.E; + exports.E1 = E; var M; (function (M) { })(M = exports.M || (exports.M = {})); - exports.M1 = exports.M; + exports.M1 = M; exports.a = M.x; exports.a1 = exports.a; }); diff --git a/tests/baselines/reference/exportsAndImports3.js b/tests/baselines/reference/exportsAndImports3.js index db29b62449e..47491ccbc04 100644 --- a/tests/baselines/reference/exportsAndImports3.js +++ b/tests/baselines/reference/exportsAndImports3.js @@ -39,25 +39,25 @@ exports.v = 1; exports.v1 = exports.v; function f() { } exports.f = f; -exports.f1 = exports.f; +exports.f1 = f; var C = (function () { function C() { } return C; })(); exports.C = C; -exports.C1 = exports.C; +exports.C1 = C; (function (E) { E[E["A"] = 0] = "A"; E[E["B"] = 1] = "B"; E[E["C"] = 2] = "C"; })(exports.E || (exports.E = {})); var E = exports.E; -exports.E1 = exports.E; +exports.E1 = E; var M; (function (M) { })(M = exports.M || (exports.M = {})); -exports.M1 = exports.M; +exports.M1 = M; exports.a = M.x; exports.a1 = exports.a; //// [t2.js] diff --git a/tests/baselines/reference/localTypes1.js b/tests/baselines/reference/localTypes1.js index d1c3758920e..09fa9c04f3c 100644 --- a/tests/baselines/reference/localTypes1.js +++ b/tests/baselines/reference/localTypes1.js @@ -202,12 +202,12 @@ function f3(b) { return a; } else { - var A = (function () { - function A() { + var A_1 = (function () { + function A_1() { } - return A; + return A_1; })(); - var c = [new A()]; + var c = [new A_1()]; c[0].x = E.B; return c; } diff --git a/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/amd/testGlo.js b/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/amd/testGlo.js index 5bdce5cf48a..1ce3452dbed 100644 --- a/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/amd/testGlo.js +++ b/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/amd/testGlo.js @@ -18,7 +18,7 @@ var m2; _super.apply(this, arguments); } return class1; - })(mExported.me.class1); + })(m2.mExported.me.class1); m2.class1 = class1; var c2 = new m2.mExported.me.class1; function f2() { @@ -31,7 +31,7 @@ var m2; _super.apply(this, arguments); } return class2; - })(mExported.me.class1); + })(m2.mExported.me.class1); m2.c3 = new mNonExported.mne.class1; function f3() { return new mNonExported.mne.class1(); diff --git a/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/node/testGlo.js b/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/node/testGlo.js index 5bdce5cf48a..1ce3452dbed 100644 --- a/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/node/testGlo.js +++ b/tests/baselines/reference/project/privacyCheckOnImportedModuleDeclarationsInsideModule/node/testGlo.js @@ -18,7 +18,7 @@ var m2; _super.apply(this, arguments); } return class1; - })(mExported.me.class1); + })(m2.mExported.me.class1); m2.class1 = class1; var c2 = new m2.mExported.me.class1; function f2() { @@ -31,7 +31,7 @@ var m2; _super.apply(this, arguments); } return class2; - })(mExported.me.class1); + })(m2.mExported.me.class1); m2.c3 = new mNonExported.mne.class1; function f3() { return new mNonExported.mne.class1(); From a73bf31c86fb94b381069843d67e4fb85c9c107f Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Fri, 5 Jun 2015 13:47:40 +0800 Subject: [PATCH 18/40] Fixes CR feedback --- src/compiler/checker.ts | 91 ++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0ba81bfa124..02e20888c9a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1349,24 +1349,30 @@ module ts { writer.writeSpace(" "); } - function getWriteResult(info: T, enclosingDeclaration: Node, flags: U, buildDisplay: (info: T, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: U) => void): string { + function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { let writer = getSingleLineStringWriter(); - buildDisplay(info, writer, enclosingDeclaration, flags); + getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning); let result = writer.string(); releaseStringWriter(writer); + return result; } - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { - return getWriteResult(symbol, enclosingDeclaration, meaning, getSymbolDisplayBuilder().buildSymbolDisplay); - } - function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - return getWriteResult(signature, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildSignatureDisplay); + let writer = getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); + let result = writer.string(); + releaseStringWriter(writer); + + return result; } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - let result = getWriteResult(type, enclosingDeclaration, flags, getSymbolDisplayBuilder().buildTypeDisplay); + let writer = getSingleLineStringWriter(); + getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); + let result = writer.string(); + releaseStringWriter(writer); + let maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; if (maxLength && result.length >= maxLength) { result = result.substr(0, maxLength - "...".length) + "..."; @@ -3234,17 +3240,16 @@ module ts { if (classType) { returnType = classType; } - else if (declaration.type && declaration.type.kind === SyntaxKind.TypePredicate) { - returnType = booleanType; - let typePredicateNode = declaration.type; - typePredicate = { - parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, - parameterIndex: typePredicateNode.parameterName ? getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName) : undefined, - type: getTypeFromTypeNode(typePredicateNode.type) - }; - } else if (declaration.type) { returnType = getTypeFromTypeNode(declaration.type); + if (declaration.type.kind === SyntaxKind.TypePredicate) { + let typePredicateNode = declaration.type; + typePredicate = { + parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined, + parameterIndex: typePredicateNode.parameterName ? getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName) : undefined, + type: getTypeFromTypeNode(typePredicateNode.type) + }; + } } else { // TypeScript 1.0 spec (April 2014): @@ -3850,6 +3855,8 @@ module ts { return getTypeFromStringLiteral(node); case SyntaxKind.TypeReference: return getTypeFromTypeReferenceOrExpressionWithTypeArguments(node); + case SyntaxKind.TypePredicate: + return booleanType; case SyntaxKind.ExpressionWithTypeArguments: return getTypeFromTypeReferenceOrExpressionWithTypeArguments(node); case SyntaxKind.TypeQuery: @@ -4654,16 +4661,18 @@ module ts { } if (source.typePredicate && target.typePredicate) { - let hasDifferentParamaterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex; + let hasDifferentParameterIndex = source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex; let hasDifferentTypes: boolean; - if (hasDifferentParamaterIndex || (hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type))) { + if (hasDifferentParameterIndex || + (hasDifferentTypes = !isTypeIdenticalTo(source.typePredicate.type, target.typePredicate.type))) { + if (reportErrors) { let sourceParamText = source.typePredicate.parameterName; let targetParamText = target.typePredicate.parameterName; let sourceTypeText = typeToString(source.typePredicate.type); let targetTypeText = typeToString(target.typePredicate.type); - if (hasDifferentParamaterIndex) { + if (hasDifferentParameterIndex) { reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceParamText, targetParamText); @@ -5651,34 +5660,21 @@ module ts { return originalType; } - function shouldNarrowTypeByTypePredicate(signature: Signature, expr: CallExpression): boolean { - if (!signature.typePredicate) { - return false; - } - if (expr.arguments && - expr.arguments[signature.typePredicate.parameterIndex] && - getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { - - return true; - } - return false; - } - function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type { if (type.flags & TypeFlags.Any) { return type; } let signature = getResolvedSignature(expr); - if (!assumeTrue) { - if (type.flags & TypeFlags.Union && - signature.typePredicate && - getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { - return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); + if (signature.typePredicate && + getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) { + + if (!assumeTrue) { + if (type.flags & TypeFlags.Union) { + return getUnionType(filter((type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type))); + } + return type; } - return type; - } - if (shouldNarrowTypeByTypePredicate(signature, expr)) { return getOptionalNarrowedType(type, signature.typePredicate.type); } return type; @@ -8624,19 +8620,20 @@ module ts { if (node.type) { if (node.type.kind === SyntaxKind.TypePredicate) { let typePredicate = getSignatureFromDeclaration(node).typePredicate; - if ((node.type).type.kind === SyntaxKind.TypePredicate) { - error((node.type).type, + let typePredicateNode = node.type; + if (typePredicateNode.type.kind === SyntaxKind.TypePredicate) { + error(typePredicateNode.type, Diagnostics.Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate, - getTextOfNode((node.type).type)); + getTextOfNode(typePredicateNode.type)); } else { if (typePredicate.parameterIndex >= 0) { checkTypeAssignableTo(typePredicate.type, getTypeAtLocation(node.parameters[typePredicate.parameterIndex]), - (node.type).type); + typePredicateNode.type); } - else if ((node.type).parameterName) { - error((node.type).parameterName, + else if (typePredicateNode.parameterName) { + error(typePredicateNode.parameterName, Diagnostics.Cannot_find_parameter_0, typePredicate.parameterName); } From fa9a914648ea0e528a1a3398c1f47fc37e676efc Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Fri, 5 Jun 2015 16:36:02 +0800 Subject: [PATCH 19/40] Adds error for non-return positioned type predicates and changed parse type predicate logic --- src/compiler/checker.ts | 10 ++++-- .../diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/parser.ts | 36 ++++++++----------- src/compiler/types.ts | 1 - .../typeGuardFunctionErrors.errors.txt | 23 +++++++++--- .../reference/typeGuardFunctionErrors.js | 16 ++++++++- .../typeGuards/typeGuardFunctionErrors.ts | 7 ++++ 8 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 02e20888c9a..72bfc80ac49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8623,8 +8623,7 @@ module ts { let typePredicateNode = node.type; if (typePredicateNode.type.kind === SyntaxKind.TypePredicate) { error(typePredicateNode.type, - Diagnostics.Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate, - getTextOfNode(typePredicateNode.type)); + Diagnostics.Type_predicates_are_only_allowed_in_return_type_position); } else { if (typePredicate.parameterIndex >= 0) { @@ -11303,6 +11302,13 @@ module ts { return checkAccessorDeclaration(node); case SyntaxKind.TypeReference: return checkTypeReferenceNode(node); + case SyntaxKind.TypePredicate: + // Issue an error every time we encounter a type predicate. They are only allowed + // in return type positions in signature declarations. checkSignatureDeclaration(..) + // already have a specific check for type predicates, so every time we encounter a type + // predicate in checkSourceElement it must be in a non return type position. + error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position); + return; case SyntaxKind.TypeQuery: return checkTypeQuery(node); case SyntaxKind.TypeLiteral: diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index a949c5c034e..1457b52ba70 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -183,7 +183,7 @@ module ts { Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate: { code: 1228, category: DiagnosticCategory.Error, key: "Cannot define type predicate '{0}' as a type to a type predicate." }, + Type_predicates_are_only_allowed_in_return_type_position: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a3e4e8c6e52..3c323f1402b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -719,7 +719,7 @@ "category": "Error", "code": 1227 }, - "Cannot define type predicate '{0}' as a type to a type predicate.": { + "Type predicates are only allowed in return type position.": { "category": "Error", "code": 1228 }, diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9a1ec116680..86c7ee98a06 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1900,9 +1900,17 @@ module ts { // TYPES - function parseTypeReference(): TypeReferenceNode { - let node = createNode(SyntaxKind.TypeReference); - node.typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); + function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode { + let typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); + if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword) { + nextToken(); + let node = createNode(SyntaxKind.TypePredicate, typeName.pos); + node.parameterName = typeName; + node.type = parseType(); + return finishNode(node); + } + let node = createNode(SyntaxKind.TypeReference, typeName.pos); + node.typeName = typeName; if (!scanner.hasPrecedingLineBreak() && token === SyntaxKind.LessThanToken) { node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); } @@ -2339,7 +2347,7 @@ module ts { case SyntaxKind.SymbolKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. let node = tryParse(parseKeywordAndNoDot); - return node || parseTypeReference(); + return node || parseTypeReferenceOrTypePredicate(); case SyntaxKind.VoidKeyword: return parseTokenNode(); case SyntaxKind.TypeOfKeyword: @@ -2351,7 +2359,7 @@ module ts { case SyntaxKind.OpenParenToken: return parseParenthesizedType(); default: - return parseTypeReference(); + return parseTypeReferenceOrTypePredicate(); } } @@ -2464,22 +2472,6 @@ module ts { return result; } - - function parseTypePredicateOrHigher(): TypeNode { - let type = parseUnionTypeOrHigher(); - if (token === SyntaxKind.IsKeyword && - type.kind === SyntaxKind.TypeReference && - (type).typeName.kind === SyntaxKind.Identifier) { - - nextToken(); - - let typePredicate = createNode(SyntaxKind.TypePredicate, type.pos); - typePredicate.parameterName = (type).typeName; - typePredicate.type = parseType(); - return finishNode(typePredicate); - } - return type; - } function parseTypeWorker(): TypeNode { if (isStartOfFunctionType()) { @@ -2488,7 +2480,7 @@ module ts { if (token === SyntaxKind.NewKeyword) { return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); } - return parseTypePredicateOrHigher(); + return parseUnionTypeOrHigher(); } function parseTypeAnnotation(): TypeNode { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index afdfe651c67..cdcdd924b31 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -464,7 +464,6 @@ module ts { typeParameters?: NodeArray; parameters: NodeArray; type?: TypeNode; - typePredicate?: TypePredicateNode; } // SyntaxKind.VariableDeclaration diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 47479b221aa..0d5065395a9 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Type predicates are only allowed in return type position. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected. @@ -22,9 +22,12 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1225: Cannot find parameter 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS1228: Type predicates are only allowed in return type position. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS1228: Type predicates are only allowed in return type position. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS1228: Type predicates are only allowed in return type position. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (18 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (21 errors) ==== class A { propA: number; @@ -46,7 +49,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { ~~~~~~ -!!! error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate. +!!! error TS1228: Type predicates are only allowed in return type position. return true; } @@ -159,4 +162,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56) declare function destructureParameter({ p1, p2, p3 }): p1 is A; ~~ !!! error TS1225: Cannot find parameter 'p1'. - \ No newline at end of file + + // Type predicates in non-return type positions + var b1: b is A; + ~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position. + function b2(a: b is A) {}; + ~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position. + function b3(): A | b is A { + ~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position. + return true; + }; \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 84dd534f9d2..0617cc1495a 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -91,7 +91,13 @@ assign3 = function(p1, p2, p3): p1 is A { // Type guard paramater referring to a binding pattern declare function destructureParameter({ p1, p2, p3 }): p1 is A; - + +// Type predicates in non-return type positions +var b1: b is A; +function b2(a: b is A) {}; +function b3(): A | b is A { + return true; +}; //// [typeGuardFunctionErrors.js] var __extends = (this && this.__extends) || function (d, b) { @@ -169,3 +175,11 @@ var assign3; assign3 = function (p1, p2, p3) { return true; }; +// Type predicates in non-return type positions +var b1; +function b2(a) { } +; +function b3() { + return true; +} +; diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts index 28a512aca6d..baae822ec2d 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -90,3 +90,10 @@ assign3 = function(p1, p2, p3): p1 is A { // Type guard paramater referring to a binding pattern declare function destructureParameter({ p1, p2, p3 }): p1 is A; + +// Type predicates in non-return type positions +var b1: b is A; +function b2(a: b is A) {}; +function b3(): A | b is A { + return true; +}; \ No newline at end of file From cc858071033b9daa8ee2d664655a59b422f5776b Mon Sep 17 00:00:00 2001 From: SaschaNaz Date: Fri, 5 Jun 2015 20:54:22 +0900 Subject: [PATCH 20/40] adding iterators to DOM interfaces --- Jakefile.js | 5 +++-- src/lib/dom.es6.d.ts | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/lib/dom.es6.d.ts diff --git a/Jakefile.js b/Jakefile.js index d447ac660ef..1d6984a1782 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -145,11 +145,12 @@ var harnessSources = [ var librarySourceMap = [ { target: "lib.core.d.ts", sources: ["core.d.ts"] }, { target: "lib.dom.d.ts", sources: ["importcore.d.ts", "extensions.d.ts", "intl.d.ts", "dom.generated.d.ts"], }, + { target: "lib.dom.es6.d.ts", sources: ["importcore.d.ts", "es6.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts"] }, { target: "lib.webworker.d.ts", sources: ["importcore.d.ts", "extensions.d.ts", "intl.d.ts", "webworker.generated.d.ts"], }, { target: "lib.scriptHost.d.ts", sources: ["importcore.d.ts", "scriptHost.d.ts"], }, { target: "lib.d.ts", sources: ["core.d.ts", "extensions.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"], }, { target: "lib.core.es6.d.ts", sources: ["core.d.ts", "es6.d.ts"]}, - { target: "lib.es6.d.ts", sources: ["core.d.ts", "es6.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"]}, + { target: "lib.es6.d.ts", sources: ["core.d.ts", "es6.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] }, ]; var libraryTargets = librarySourceMap.map(function (f) { @@ -690,4 +691,4 @@ task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function complete(); }); ex.run(); -}, { async: true }); +}, { async: true }); diff --git a/src/lib/dom.es6.d.ts b/src/lib/dom.es6.d.ts new file mode 100644 index 00000000000..8702201bb9e --- /dev/null +++ b/src/lib/dom.es6.d.ts @@ -0,0 +1,11 @@ +interface DOMTokenList { + [Symbol.iterator](): IterableIterator; +} + +interface NodeList { + [Symbol.iterator](): IterableIterator +} + +interface NodeListOf { + [Symbol.iterator](): IterableIterator +} \ No newline at end of file From 9c6e6acf973b394b3f29608a5caabb2c0bdeb425 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 5 Jun 2015 14:28:57 -0700 Subject: [PATCH 21/40] Support generic type aliases --- src/compiler/binder.ts | 2 + src/compiler/checker.ts | 144 ++++++++++++++++++++++------------------ src/compiler/parser.ts | 2 + src/compiler/types.ts | 5 +- 4 files changed, 89 insertions(+), 64 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ea589891241..9f7f36d10d0 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -338,6 +338,7 @@ module ts { case SyntaxKind.ArrowFunction: case SyntaxKind.ModuleDeclaration: case SyntaxKind.SourceFile: + case SyntaxKind.TypeAliasDeclaration: return ContainerFlags.IsContainerWithLocals; case SyntaxKind.CatchClause: @@ -424,6 +425,7 @@ module ts { case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: + case SyntaxKind.TypeAliasDeclaration: // All the children of these container types are never visible through another // symbol (i.e. through another symbol's 'exports' or 'members'). Instead, // they're only accessed 'lexically' (i.e. from code that exists underneath diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 28242aba015..40e98b44148 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2577,8 +2577,8 @@ module ts { function getLocalTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] { let result: TypeParameter[]; for (let node of symbol.declarations) { - if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration) { - let declaration = node; + if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.TypeAliasDeclaration) { + let declaration = node; if (declaration.typeParameters) { result = appendTypeParameters(result, declaration.typeParameters); } @@ -2593,6 +2593,15 @@ module ts { return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterface(symbol)); } + function getTypeParametersOfTypeAlias(symbol: Symbol): TypeParameter[] { + let links = getSymbolLinks(symbol); + if (!links.typeParameters) { + let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + links.typeParameters = declaration.typeParameters ? appendTypeParameters(undefined, declaration.typeParameters) : emptyArray; + } + return links.typeParameters; + } + function getBaseTypes(type: InterfaceType): ObjectType[] { let typeWithBaseTypes = type; if (!typeWithBaseTypes.baseTypes) { @@ -3513,72 +3522,79 @@ module ts { } } - function getTypeFromTypeReferenceOrExpressionWithTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments): Type { - let links = getNodeLinks(node); - if (!links.resolvedType) { - let type: Type; - - // We don't currently support heritage clauses with complex expressions in them. - // For these cases, we just set the type to be the unknownType. - if (node.kind !== SyntaxKind.ExpressionWithTypeArguments || isSupportedExpressionWithTypeArguments(node)) { - let typeNameOrExpression = node.kind === SyntaxKind.TypeReference - ? (node).typeName - : (node).expression; - - let symbol = resolveEntityName(typeNameOrExpression, SymbolFlags.Type); - if (symbol) { - if ((symbol.flags & SymbolFlags.TypeParameter) && isTypeParameterReferenceIllegalInConstraint(node, symbol)) { - // TypeScript 1.0 spec (April 2014): 3.4.1 - // Type parameters declared in a particular type parameter list - // may not be referenced in constraints in that type parameter list - // Implementation: such type references are resolved to 'unknown' type that usually denotes error - type = unknownType; - } - else { - type = createTypeReferenceIfGeneric( - getDeclaredTypeOfSymbol(symbol), - node, node.typeArguments); - } - } + function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { + let type = getDeclaredTypeOfSymbol(symbol); + let typeParameters = (type).localTypeParameters; + if (typeParameters) { + if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) { + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); + return unknownType; } - - links.resolvedType = type || unknownType; - } - - return links.resolvedType; - } - - function createTypeReferenceIfGeneric(type: Type, node: Node, typeArguments: NodeArray): Type { - if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) { // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - let localTypeParameters = (type).localTypeParameters; - let expectedTypeArgCount = localTypeParameters ? localTypeParameters.length : 0; - let typeArgCount = typeArguments ? typeArguments.length : 0; - if (typeArgCount === expectedTypeArgCount) { - // When no type arguments are expected we already have the right type because all outer type parameters - // have themselves as default type arguments. - if (typeArgCount) { - return createTypeReference(type, concatenate((type).outerTypeParameters, - map(typeArguments, getTypeFromTypeNode))); - } - } - else { - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), expectedTypeArgCount); - return undefined; - } + return createTypeReference(type, concatenate((type).outerTypeParameters, + map(node.typeArguments, getTypeFromTypeNode))); } - else { - if (typeArguments) { - error(node, Diagnostics.Type_0_is_not_generic, typeToString(type)); - return undefined; - } + if (node.typeArguments) { + error(node, Diagnostics.Type_0_is_not_generic, typeToString(type)); + return unknownType; } - return type; } + function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { + let type = getDeclaredTypeOfSymbol(symbol); + let typeParameters = getTypeParametersOfTypeAlias(symbol); + if (typeParameters.length) { + if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) { + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, symbolToString(symbol), typeParameters.length); + return unknownType; + } + let typeArguments = map(node.typeArguments, getTypeFromTypeNode); + let id = getTypeListId(typeArguments); + let links = getSymbolLinks(symbol); + if (!links.instantiations) { + links.instantiations = {}; + // The declared type corresponds to an instantiation with its own type parameters as type arguments + links.instantiations[getTypeListId(typeParameters)] = type; + } + return links.instantiations[id] || (links.instantiations[id] = instantiateType(type, createTypeMapper(typeParameters, typeArguments))); + } + if (node.typeArguments) { + error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol)); + return unknownType; + } + return type; + } + + function getTypeFromTypeParameterReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // Type parameters declared in a particular type parameter list + // may not be referenced in constraints in that type parameter list + // Implementation: such type references are resolved to 'unknown' type that usually denotes error + return isTypeParameterReferenceIllegalInConstraint(node, symbol) ? unknownType : getDeclaredTypeOfSymbol(symbol); + } + + function getTypeFromTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + // We only support expressions that are simple qualified names. For other expressions this produces undefined. let typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName : + isSupportedExpressionWithTypeArguments(node) ? (node).expression : + undefined; + let symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; + let type = symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) : + symbol.flags & SymbolFlags.TypeParameter ? getTypeFromTypeParameterReference(node, symbol) : + symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) : + getDeclaredTypeOfSymbol(symbol); + // Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the + // type reference in checkTypeReferenceOrExpressionWithTypeArguments. + links.resolvedSymbol = symbol; + links.resolvedType = type; + } + return links.resolvedType; + } + function getTypeFromTypeQueryNode(node: TypeQueryNode): Type { let links = getNodeLinks(node); if (!links.resolvedType) { @@ -3848,9 +3864,9 @@ module ts { case SyntaxKind.StringLiteral: return getTypeFromStringLiteral(node); case SyntaxKind.TypeReference: - return getTypeFromTypeReferenceOrExpressionWithTypeArguments(node); + return getTypeFromTypeReference(node); case SyntaxKind.ExpressionWithTypeArguments: - return getTypeFromTypeReferenceOrExpressionWithTypeArguments(node); + return getTypeFromTypeReference(node); case SyntaxKind.TypeQuery: return getTypeFromTypeQueryNode(node); case SyntaxKind.ArrayType: @@ -8766,13 +8782,15 @@ module ts { // Grammar checking checkGrammarTypeArguments(node, node.typeArguments); - let type = getTypeFromTypeReferenceOrExpressionWithTypeArguments(node); + let type = getTypeFromTypeReference(node); if (type !== unknownType && node.typeArguments) { // Do type argument local checks only if referenced type is successfully resolved + let symbol = getNodeLinks(node).resolvedSymbol; + let typeParameters = symbol.flags & SymbolFlags.TypeAlias ? getTypeParametersOfTypeAlias(symbol) : (type).target.localTypeParameters; let len = node.typeArguments.length; for (let i = 0; i < len; i++) { checkSourceElement(node.typeArguments[i]); - let constraint = getConstraintOfTypeParameter((type).target.typeParameters[i]); + let constraint = getConstraintOfTypeParameter(typeParameters[i]); if (produceDiagnostics && constraint) { let typeArgument = (type).typeArguments[i]; checkTypeAssignableTo(typeArgument, constraint, node, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 80c70a250fb..e15c6184e88 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -255,6 +255,7 @@ module ts { return visitNodes(cbNodes, node.decorators) || visitNodes(cbNodes, node.modifiers) || visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).typeParameters) || visitNode(cbNode, (node).type); case SyntaxKind.EnumDeclaration: return visitNodes(cbNodes, node.decorators) || @@ -4547,6 +4548,7 @@ module ts { setModifiers(node, modifiers); parseExpected(SyntaxKind.TypeKeyword); node.name = parseIdentifier(); + node.typeParameters = parseTypeParameters(); parseExpected(SyntaxKind.EqualsToken); node.type = parseType(); parseSemicolon(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d4e1378772b..4f37869b5bf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -939,6 +939,7 @@ module ts { export interface TypeAliasDeclaration extends Declaration, Statement { name: Identifier; + typeParameters?: NodeArray; type: TypeNode; } @@ -1525,7 +1526,9 @@ module ts { export interface SymbolLinks { target?: Symbol; // Resolved (non-alias) target of an alias type?: Type; // Type of value symbol - declaredType?: Type; // Type of class, interface, enum, or type parameter + declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter + typeParameters?: TypeParameter[]; // Type parameters of type alias (empty array if none) + instantiations?: Map; // Instantiations of generic type alias 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 From eb8a0e8d56feca431570df1ecadf630076d7963e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 5 Jun 2015 14:30:14 -0700 Subject: [PATCH 22/40] Accepting new baselines --- .../reference/typeAliasesForObjectTypes.errors.txt | 11 +---------- .../baselines/reference/typeAliasesForObjectTypes.js | 3 --- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt b/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt index 45e3c2da32f..d5bc01f93ba 100644 --- a/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt +++ b/tests/baselines/reference/typeAliasesForObjectTypes.errors.txt @@ -2,12 +2,9 @@ tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(4,22): er tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(5,21): error TS2422: A class may only implement another class or interface. tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(10,6): error TS2300: Duplicate identifier 'T2'. tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(11,6): error TS2300: Duplicate identifier 'T2'. -tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(14,8): error TS1005: '=' expected. -tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(14,12): error TS1005: '(' expected. -tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(14,19): error TS2304: Cannot find name 'T'. -==== tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts (7 errors) ==== +==== tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts (4 errors) ==== type T1 = { x: string } // An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot. @@ -30,10 +27,4 @@ tests/cases/conformance/types/typeAliases/typeAliasesForObjectTypes.ts(14,19): e // An interface can have type parameters, but a type alias for an object type literal cannot. type T3 = { x: T } - ~ -!!! error TS1005: '=' expected. - ~ -!!! error TS1005: '(' expected. - ~ -!!! error TS2304: Cannot find name 'T'. \ No newline at end of file diff --git a/tests/baselines/reference/typeAliasesForObjectTypes.js b/tests/baselines/reference/typeAliasesForObjectTypes.js index eb1ec7f130a..0b583528ade 100644 --- a/tests/baselines/reference/typeAliasesForObjectTypes.js +++ b/tests/baselines/reference/typeAliasesForObjectTypes.js @@ -21,6 +21,3 @@ var C1 = (function () { } return C1; })(); -{ - x: T; -} From bcdbc98dacb12a3a11aa029a084d26b349b8e014 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 5 Jun 2015 14:50:15 -0700 Subject: [PATCH 23/40] Adding simple tests --- .../baselines/reference/genericTypeAliases.js | 120 ++++++++ .../reference/genericTypeAliases.symbols | 231 +++++++++++++++ .../reference/genericTypeAliases.types | 274 ++++++++++++++++++ .../types/typeAliases/genericTypeAliases.ts | 73 +++++ 4 files changed, 698 insertions(+) create mode 100644 tests/baselines/reference/genericTypeAliases.js create mode 100644 tests/baselines/reference/genericTypeAliases.symbols create mode 100644 tests/baselines/reference/genericTypeAliases.types create mode 100644 tests/cases/conformance/types/typeAliases/genericTypeAliases.ts diff --git a/tests/baselines/reference/genericTypeAliases.js b/tests/baselines/reference/genericTypeAliases.js new file mode 100644 index 00000000000..8218f5c886c --- /dev/null +++ b/tests/baselines/reference/genericTypeAliases.js @@ -0,0 +1,120 @@ +//// [genericTypeAliases.ts] +type Tree = T | { left: Tree, right: Tree }; + +var tree: Tree = { + left: { + left: 0, + right: { + left: 1, + right: 2 + }, + }, + right: 3 +}; + +type Lazy = T | (() => T); + +var ls: Lazy; +ls = "eager"; +ls = () => "lazy"; + +type Foo = T | { x: Foo }; +type Bar = U | { x: Bar }; + +// Deeply instantiated generics +var x: Foo; +var y: Bar; +x = y; +y = x; + +x = "string"; +x = { x: "hello" }; +x = { x: { x: "world" } }; + +var z: Foo; +z = 42; +z = { x: 42 }; +z = { x: { x: 42 } }; + +type Strange = string; // Type parameter not used +var s: Strange; +s = "hello"; + +interface Tuple { + a: A; + b: B; +} + +type Pair = Tuple; + +interface TaggedPair extends Pair { + tag: string; +} + +var p: TaggedPair; +p.a = 1; +p.b = 2; +p.tag = "test"; + +function f() { + type Foo = T | { x: Foo }; + var x: Foo; + return x; +} + +function g() { + type Bar = U | { x: Bar }; + var x: Bar; + return x; +} + +// Deeply instantiated generics +var a = f(); +var b = g(); +a = b; + + +//// [genericTypeAliases.js] +var tree = { + left: { + left: 0, + right: { + left: 1, + right: 2 + } + }, + right: 3 +}; +var ls; +ls = "eager"; +ls = function () { return "lazy"; }; +// Deeply instantiated generics +var x; +var y; +x = y; +y = x; +x = "string"; +x = { x: "hello" }; +x = { x: { x: "world" } }; +var z; +z = 42; +z = { x: 42 }; +z = { x: { x: 42 } }; +var s; +s = "hello"; +var p; +p.a = 1; +p.b = 2; +p.tag = "test"; +function f() { + var x; + return x; +} +function g() { + var x; + return x; +} +// Deeply instantiated generics +var a = f(); +var b = g(); +a = b; diff --git a/tests/baselines/reference/genericTypeAliases.symbols b/tests/baselines/reference/genericTypeAliases.symbols new file mode 100644 index 00000000000..1a1d0e51487 --- /dev/null +++ b/tests/baselines/reference/genericTypeAliases.symbols @@ -0,0 +1,231 @@ +=== tests/cases/conformance/types/typeAliases/genericTypeAliases.ts === +type Tree = T | { left: Tree, right: Tree }; +>Tree : Symbol(Tree, Decl(genericTypeAliases.ts, 0, 0)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 0, 10)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 0, 10)) +>left : Symbol(left, Decl(genericTypeAliases.ts, 0, 20)) +>Tree : Symbol(Tree, Decl(genericTypeAliases.ts, 0, 0)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 0, 10)) +>right : Symbol(right, Decl(genericTypeAliases.ts, 0, 35)) +>Tree : Symbol(Tree, Decl(genericTypeAliases.ts, 0, 0)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 0, 10)) + +var tree: Tree = { +>tree : Symbol(tree, Decl(genericTypeAliases.ts, 2, 3)) +>Tree : Symbol(Tree, Decl(genericTypeAliases.ts, 0, 0)) + + left: { +>left : Symbol(left, Decl(genericTypeAliases.ts, 2, 26)) + + left: 0, +>left : Symbol(left, Decl(genericTypeAliases.ts, 3, 11)) + + right: { +>right : Symbol(right, Decl(genericTypeAliases.ts, 4, 16)) + + left: 1, +>left : Symbol(left, Decl(genericTypeAliases.ts, 5, 16)) + + right: 2 +>right : Symbol(right, Decl(genericTypeAliases.ts, 6, 20)) + + }, + }, + right: 3 +>right : Symbol(right, Decl(genericTypeAliases.ts, 9, 6)) + +}; + +type Lazy = T | (() => T); +>Lazy : Symbol(Lazy, Decl(genericTypeAliases.ts, 11, 2)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 13, 10)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 13, 10)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 13, 10)) + +var ls: Lazy; +>ls : Symbol(ls, Decl(genericTypeAliases.ts, 15, 3)) +>Lazy : Symbol(Lazy, Decl(genericTypeAliases.ts, 11, 2)) + +ls = "eager"; +>ls : Symbol(ls, Decl(genericTypeAliases.ts, 15, 3)) + +ls = () => "lazy"; +>ls : Symbol(ls, Decl(genericTypeAliases.ts, 15, 3)) + +type Foo = T | { x: Foo }; +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 17, 18)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 19, 9)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 19, 9)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 19, 19)) +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 17, 18)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 19, 9)) + +type Bar = U | { x: Bar }; +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 19, 32)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 20, 9)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 20, 9)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 20, 19)) +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 19, 32)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 20, 9)) + +// Deeply instantiated generics +var x: Foo; +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 17, 18)) + +var y: Bar; +>y : Symbol(y, Decl(genericTypeAliases.ts, 24, 3)) +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 19, 32)) + +x = y; +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) +>y : Symbol(y, Decl(genericTypeAliases.ts, 24, 3)) + +y = x; +>y : Symbol(y, Decl(genericTypeAliases.ts, 24, 3)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) + +x = "string"; +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) + +x = { x: "hello" }; +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 29, 5)) + +x = { x: { x: "world" } }; +>x : Symbol(x, Decl(genericTypeAliases.ts, 23, 3)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 30, 5)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 30, 10)) + +var z: Foo; +>z : Symbol(z, Decl(genericTypeAliases.ts, 32, 3)) +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 17, 18)) + +z = 42; +>z : Symbol(z, Decl(genericTypeAliases.ts, 32, 3)) + +z = { x: 42 }; +>z : Symbol(z, Decl(genericTypeAliases.ts, 32, 3)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 34, 5)) + +z = { x: { x: 42 } }; +>z : Symbol(z, Decl(genericTypeAliases.ts, 32, 3)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 35, 5)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 35, 10)) + +type Strange = string; // Type parameter not used +>Strange : Symbol(Strange, Decl(genericTypeAliases.ts, 35, 21)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 37, 13)) + +var s: Strange; +>s : Symbol(s, Decl(genericTypeAliases.ts, 38, 3)) +>Strange : Symbol(Strange, Decl(genericTypeAliases.ts, 35, 21)) + +s = "hello"; +>s : Symbol(s, Decl(genericTypeAliases.ts, 38, 3)) + +interface Tuple { +>Tuple : Symbol(Tuple, Decl(genericTypeAliases.ts, 39, 12)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 41, 16)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 41, 18)) + + a: A; +>a : Symbol(a, Decl(genericTypeAliases.ts, 41, 23)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 41, 16)) + + b: B; +>b : Symbol(b, Decl(genericTypeAliases.ts, 42, 9)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 41, 18)) +} + +type Pair = Tuple; +>Pair : Symbol(Pair, Decl(genericTypeAliases.ts, 44, 1)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) +>Tuple : Symbol(Tuple, Decl(genericTypeAliases.ts, 39, 12)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) + +interface TaggedPair extends Pair { +>TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 27)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 48, 21)) +>Pair : Symbol(Pair, Decl(genericTypeAliases.ts, 44, 1)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 48, 21)) + + tag: string; +>tag : Symbol(tag, Decl(genericTypeAliases.ts, 48, 41)) +} + +var p: TaggedPair; +>p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) +>TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 27)) + +p.a = 1; +>p.a : Symbol(Tuple.a, Decl(genericTypeAliases.ts, 41, 23)) +>p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) +>a : Symbol(Tuple.a, Decl(genericTypeAliases.ts, 41, 23)) + +p.b = 2; +>p.b : Symbol(Tuple.b, Decl(genericTypeAliases.ts, 42, 9)) +>p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) +>b : Symbol(Tuple.b, Decl(genericTypeAliases.ts, 42, 9)) + +p.tag = "test"; +>p.tag : Symbol(TaggedPair.tag, Decl(genericTypeAliases.ts, 48, 41)) +>p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) +>tag : Symbol(TaggedPair.tag, Decl(genericTypeAliases.ts, 48, 41)) + +function f() { +>f : Symbol(f, Decl(genericTypeAliases.ts, 55, 15)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 57, 11)) + + type Foo = T | { x: Foo }; +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 57, 17)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 58, 13)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 58, 13)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 58, 23)) +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 57, 17)) +>T : Symbol(T, Decl(genericTypeAliases.ts, 58, 13)) + + var x: Foo; +>x : Symbol(x, Decl(genericTypeAliases.ts, 59, 7)) +>Foo : Symbol(Foo, Decl(genericTypeAliases.ts, 57, 17)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 57, 11)) + + return x; +>x : Symbol(x, Decl(genericTypeAliases.ts, 59, 7)) +} + +function g() { +>g : Symbol(g, Decl(genericTypeAliases.ts, 61, 1)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 63, 11)) + + type Bar = U | { x: Bar }; +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 63, 17)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 64, 13)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 64, 13)) +>x : Symbol(x, Decl(genericTypeAliases.ts, 64, 23)) +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 63, 17)) +>U : Symbol(U, Decl(genericTypeAliases.ts, 64, 13)) + + var x: Bar; +>x : Symbol(x, Decl(genericTypeAliases.ts, 65, 7)) +>Bar : Symbol(Bar, Decl(genericTypeAliases.ts, 63, 17)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 63, 11)) + + return x; +>x : Symbol(x, Decl(genericTypeAliases.ts, 65, 7)) +} + +// Deeply instantiated generics +var a = f(); +>a : Symbol(a, Decl(genericTypeAliases.ts, 70, 3)) +>f : Symbol(f, Decl(genericTypeAliases.ts, 55, 15)) + +var b = g(); +>b : Symbol(b, Decl(genericTypeAliases.ts, 71, 3)) +>g : Symbol(g, Decl(genericTypeAliases.ts, 61, 1)) + +a = b; +>a : Symbol(a, Decl(genericTypeAliases.ts, 70, 3)) +>b : Symbol(b, Decl(genericTypeAliases.ts, 71, 3)) + diff --git a/tests/baselines/reference/genericTypeAliases.types b/tests/baselines/reference/genericTypeAliases.types new file mode 100644 index 00000000000..b43e2610725 --- /dev/null +++ b/tests/baselines/reference/genericTypeAliases.types @@ -0,0 +1,274 @@ +=== tests/cases/conformance/types/typeAliases/genericTypeAliases.ts === +type Tree = T | { left: Tree, right: Tree }; +>Tree : T | { left: T | any; right: T | any; } +>T : T +>T : T +>left : T | { left: T | any; right: T | any; } +>Tree : T | { left: T | any; right: T | any; } +>T : T +>right : T | { left: T | any; right: T | any; } +>Tree : T | { left: T | any; right: T | any; } +>T : T + +var tree: Tree = { +>tree : number | { left: number | any; right: number | any; } +>Tree : T | { left: T | any; right: T | any; } +>{ left: { left: 0, right: { left: 1, right: 2 }, }, right: 3} : { left: { left: number; right: { left: number; right: number; }; }; right: number; } + + left: { +>left : { left: number; right: { left: number; right: number; }; } +>{ left: 0, right: { left: 1, right: 2 }, } : { left: number; right: { left: number; right: number; }; } + + left: 0, +>left : number +>0 : number + + right: { +>right : { left: number; right: number; } +>{ left: 1, right: 2 } : { left: number; right: number; } + + left: 1, +>left : number +>1 : number + + right: 2 +>right : number +>2 : number + + }, + }, + right: 3 +>right : number +>3 : number + +}; + +type Lazy = T | (() => T); +>Lazy : T | (() => T) +>T : T +>T : T +>T : T + +var ls: Lazy; +>ls : string | (() => string) +>Lazy : T | (() => T) + +ls = "eager"; +>ls = "eager" : string +>ls : string | (() => string) +>"eager" : string + +ls = () => "lazy"; +>ls = () => "lazy" : () => string +>ls : string | (() => string) +>() => "lazy" : () => string +>"lazy" : string + +type Foo = T | { x: Foo }; +>Foo : T | { x: T | any; } +>T : T +>T : T +>x : T | { x: T | any; } +>Foo : T | { x: T | any; } +>T : T + +type Bar = U | { x: Bar }; +>Bar : U | { x: U | any; } +>U : U +>U : U +>x : U | { x: U | any; } +>Bar : U | { x: U | any; } +>U : U + +// Deeply instantiated generics +var x: Foo; +>x : string | { x: string | any; } +>Foo : T | { x: T | any; } + +var y: Bar; +>y : string | { x: string | any; } +>Bar : U | { x: U | any; } + +x = y; +>x = y : string | { x: string | any; } +>x : string | { x: string | any; } +>y : string | { x: string | any; } + +y = x; +>y = x : string | { x: string | any; } +>y : string | { x: string | any; } +>x : string | { x: string | any; } + +x = "string"; +>x = "string" : string +>x : string | { x: string | any; } +>"string" : string + +x = { x: "hello" }; +>x = { x: "hello" } : { x: string; } +>x : string | { x: string | any; } +>{ x: "hello" } : { x: string; } +>x : string +>"hello" : string + +x = { x: { x: "world" } }; +>x = { x: { x: "world" } } : { x: { x: string; }; } +>x : string | { x: string | any; } +>{ x: { x: "world" } } : { x: { x: string; }; } +>x : { x: string; } +>{ x: "world" } : { x: string; } +>x : string +>"world" : string + +var z: Foo; +>z : number | { x: number | any; } +>Foo : T | { x: T | any; } + +z = 42; +>z = 42 : number +>z : number | { x: number | any; } +>42 : number + +z = { x: 42 }; +>z = { x: 42 } : { x: number; } +>z : number | { x: number | any; } +>{ x: 42 } : { x: number; } +>x : number +>42 : number + +z = { x: { x: 42 } }; +>z = { x: { x: 42 } } : { x: { x: number; }; } +>z : number | { x: number | any; } +>{ x: { x: 42 } } : { x: { x: number; }; } +>x : { x: number; } +>{ x: 42 } : { x: number; } +>x : number +>42 : number + +type Strange = string; // Type parameter not used +>Strange : string +>T : T + +var s: Strange; +>s : string +>Strange : string + +s = "hello"; +>s = "hello" : string +>s : string +>"hello" : string + +interface Tuple { +>Tuple : Tuple +>A : A +>B : B + + a: A; +>a : A +>A : A + + b: B; +>b : B +>B : B +} + +type Pair = Tuple; +>Pair : Tuple +>T : T +>Tuple : Tuple +>T : T +>T : T + +interface TaggedPair extends Pair { +>TaggedPair : TaggedPair +>T : T +>Pair : Tuple +>T : T + + tag: string; +>tag : string +} + +var p: TaggedPair; +>p : TaggedPair +>TaggedPair : TaggedPair + +p.a = 1; +>p.a = 1 : number +>p.a : number +>p : TaggedPair +>a : number +>1 : number + +p.b = 2; +>p.b = 2 : number +>p.b : number +>p : TaggedPair +>b : number +>2 : number + +p.tag = "test"; +>p.tag = "test" : string +>p.tag : string +>p : TaggedPair +>tag : string +>"test" : string + +function f() { +>f : () => A[] | { x: A[] | any; } +>A : A + + type Foo = T | { x: Foo }; +>Foo : T | { x: T | any; } +>T : T +>T : T +>x : T | { x: T | any; } +>Foo : T | { x: T | any; } +>T : T + + var x: Foo; +>x : A[] | { x: A[] | any; } +>Foo : T | { x: T | any; } +>A : A + + return x; +>x : A[] | { x: A[] | any; } +} + +function g() { +>g : () => B[] | { x: B[] | any; } +>B : B + + type Bar = U | { x: Bar }; +>Bar : U | { x: U | any; } +>U : U +>U : U +>x : U | { x: U | any; } +>Bar : U | { x: U | any; } +>U : U + + var x: Bar; +>x : B[] | { x: B[] | any; } +>Bar : U | { x: U | any; } +>B : B + + return x; +>x : B[] | { x: B[] | any; } +} + +// Deeply instantiated generics +var a = f(); +>a : string[] | { x: string[] | any; } +>f() : string[] | { x: string[] | any; } +>f : () => A[] | { x: A[] | any; } + +var b = g(); +>b : string[] | { x: string[] | any; } +>g() : string[] | { x: string[] | any; } +>g : () => B[] | { x: B[] | any; } + +a = b; +>a = b : string[] | { x: string[] | any; } +>a : string[] | { x: string[] | any; } +>b : string[] | { x: string[] | any; } + diff --git a/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts b/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts new file mode 100644 index 00000000000..e26279a8a41 --- /dev/null +++ b/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts @@ -0,0 +1,73 @@ +type Tree = T | { left: Tree, right: Tree }; + +var tree: Tree = { + left: { + left: 0, + right: { + left: 1, + right: 2 + }, + }, + right: 3 +}; + +type Lazy = T | (() => T); + +var ls: Lazy; +ls = "eager"; +ls = () => "lazy"; + +type Foo = T | { x: Foo }; +type Bar = U | { x: Bar }; + +// Deeply instantiated generics +var x: Foo; +var y: Bar; +x = y; +y = x; + +x = "string"; +x = { x: "hello" }; +x = { x: { x: "world" } }; + +var z: Foo; +z = 42; +z = { x: 42 }; +z = { x: { x: 42 } }; + +type Strange = string; // Type parameter not used +var s: Strange; +s = "hello"; + +interface Tuple { + a: A; + b: B; +} + +type Pair = Tuple; + +interface TaggedPair extends Pair { + tag: string; +} + +var p: TaggedPair; +p.a = 1; +p.b = 2; +p.tag = "test"; + +function f() { + type Foo = T | { x: Foo }; + var x: Foo; + return x; +} + +function g() { + type Bar = U | { x: Bar }; + var x: Bar; + return x; +} + +// Deeply instantiated generics +var a = f(); +var b = g(); +a = b; From 487dff564fe4ec87fc1d445475deeb86b98224d7 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 6 Jun 2015 11:27:55 +0800 Subject: [PATCH 24/40] Fixes CR feedback --- src/compiler/checker.ts | 54 +++++++++---- .../diagnosticInformationMap.generated.ts | 3 +- src/compiler/diagnosticMessages.json | 6 +- .../baselines/reference/typeGuardFunction.js | 51 ++++++++++-- .../reference/typeGuardFunction.symbols | 77 +++++++++++++++---- .../reference/typeGuardFunction.types | 67 +++++++++++++++- .../typeGuardFunctionErrors.errors.txt | 55 ++++++++++--- .../reference/typeGuardFunctionErrors.js | 49 +++++++++++- .../typeGuards/typeGuardFunction.ts | 28 ++++++- .../typeGuards/typeGuardFunctionErrors.ts | 20 ++++- 10 files changed, 352 insertions(+), 58 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 72bfc80ac49..c7ccb98f8f2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5642,13 +5642,13 @@ module ts { } if (targetType) { - return getOptionalNarrowedType(type, targetType); + return getNarrowedType(type, targetType); } return type; } - function getOptionalNarrowedType(originalType: Type, narrowedTypeCandidate: Type) { + function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type) { // Narrow to the target type if it's a subtype of the current type if (isTypeSubtypeOf(narrowedTypeCandidate, originalType)) { return narrowedTypeCandidate; @@ -5675,7 +5675,7 @@ module ts { } return type; } - return getOptionalNarrowedType(type, signature.typePredicate.type); + return getNarrowedType(type, signature.typePredicate.type); } return type; } @@ -8601,6 +8601,19 @@ module ts { } } + function isInATypePredicateCompatiblePosition(node: Node): boolean { + switch (node.parent.kind) { + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionType: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return true; + } + return false; + } + function checkSignatureDeclaration(node: SignatureDeclaration) { // Grammar checking if (node.kind === SyntaxKind.IndexSignature) { @@ -8621,15 +8634,17 @@ module ts { if (node.type.kind === SyntaxKind.TypePredicate) { let typePredicate = getSignatureFromDeclaration(node).typePredicate; let typePredicateNode = node.type; - if (typePredicateNode.type.kind === SyntaxKind.TypePredicate) { - error(typePredicateNode.type, - Diagnostics.Type_predicates_are_only_allowed_in_return_type_position); - } - else { + if (isInATypePredicateCompatiblePosition(typePredicateNode)) { if (typePredicate.parameterIndex >= 0) { - checkTypeAssignableTo(typePredicate.type, - getTypeAtLocation(node.parameters[typePredicate.parameterIndex]), - typePredicateNode.type); + if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) { + error(typePredicateNode.parameterName, + Diagnostics.Type_predicate_cannot_reference_a_spread_parameter); + } + else { + checkTypeAssignableTo(typePredicate.type, + getTypeAtLocation(node.parameters[typePredicate.parameterIndex]), + typePredicateNode.type); + } } else if (typePredicateNode.parameterName) { error(typePredicateNode.parameterName, @@ -8637,6 +8652,10 @@ module ts { typePredicate.parameterName); } } + else { + error(typePredicateNode, + Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations); + } } else { checkSourceElement(node.type); @@ -11275,6 +11294,12 @@ module ts { } } + function checkTypePredicate(node: TypePredicateNode) { + if(!isInATypePredicateCompatiblePosition(node)) { + error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations); + } + } + function checkSourceElement(node: Node): void { if (!node) return; switch (node.kind) { @@ -11303,12 +11328,7 @@ module ts { case SyntaxKind.TypeReference: return checkTypeReferenceNode(node); case SyntaxKind.TypePredicate: - // Issue an error every time we encounter a type predicate. They are only allowed - // in return type positions in signature declarations. checkSignatureDeclaration(..) - // already have a specific check for type predicates, so every time we encounter a type - // predicate in checkSourceElement it must be in a non return type position. - error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position); - return; + return checkTypePredicate(node); case SyntaxKind.TypeQuery: return checkTypeQuery(node); case SyntaxKind.TypeLiteral: diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 1457b52ba70..25d3730cc07 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -183,7 +183,8 @@ module ts { Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Type_predicates_are_only_allowed_in_return_type_position: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position." }, + Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations." }, + Type_predicate_cannot_reference_a_spread_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a spread parameter." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 3c323f1402b..4008a6af1b1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -719,10 +719,14 @@ "category": "Error", "code": 1227 }, - "Type predicates are only allowed in return type position.": { + "Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations.": { "category": "Error", "code": 1228 }, + "Type predicate cannot reference a spread parameter.": { + "category": "Error", + "code": 1229 + }, "Duplicate identifier '{0}'.": { diff --git a/tests/baselines/reference/typeGuardFunction.js b/tests/baselines/reference/typeGuardFunction.js index d6b64c09d4d..5c256160bba 100644 --- a/tests/baselines/reference/typeGuardFunction.js +++ b/tests/baselines/reference/typeGuardFunction.js @@ -21,18 +21,18 @@ declare function retC(): C; var a: A; var b: B; -// Basic. +// Basic if (isC(a)) { a.propC; } -// Sub type. +// Sub type var subType: C; if(isA(subType)) { subType.propC; } -// Union type. +// Union type var union: A | B; if(isA(union)) { union.propA; @@ -45,6 +45,27 @@ if (isC_multipleParams(a, 0)) { a.propC; } +// Methods +var obj: { + func1(p1: A): p1 is C; +} +class D { + method1(p1: A): p1 is C { + return true; + } +} + +// Arrow function +let f1 = (p1: A): p1 is C => false; + +// Function type +declare function f2(p1: (p1: A) => p1 is C); + +// Function expressions +f2(function(p1: A): p1 is C { + return true; +}); + // Evaluations are asssignable to boolean. declare function acceptingBoolean(a: boolean); acceptingBoolean(isA(a)); @@ -53,6 +74,7 @@ acceptingBoolean(isA(a)); declare function acceptingTypeGuardFunction(p1: (item) => item is A); acceptingTypeGuardFunction(isA); +// Binary expressions let union2: C | B; let union3: boolean | B = isA(union2) || union2; @@ -82,16 +104,16 @@ var C = (function (_super) { })(A); var a; var b; -// Basic. +// Basic if (isC(a)) { a.propC; } -// Sub type. +// Sub type var subType; if (isA(subType)) { subType.propC; } -// Union type. +// Union type var union; if (isA(union)) { union.propA; @@ -99,7 +121,24 @@ if (isA(union)) { if (isC_multipleParams(a, 0)) { a.propC; } +// Methods +var obj; +var D = (function () { + function D() { + } + D.prototype.method1 = function (p1) { + return true; + }; + return D; +})(); +// Arrow function +var f1 = function (p1) { return false; }; +// Function expressions +f2(function (p1) { + return true; +}); acceptingBoolean(isA(a)); acceptingTypeGuardFunction(isA); +// Binary expressions var union2; var union3 = isA(union2) || union2; diff --git a/tests/baselines/reference/typeGuardFunction.symbols b/tests/baselines/reference/typeGuardFunction.symbols index f9180d56b0b..5b5fe1ec855 100644 --- a/tests/baselines/reference/typeGuardFunction.symbols +++ b/tests/baselines/reference/typeGuardFunction.symbols @@ -49,7 +49,7 @@ var b: B; >b : Symbol(b, Decl(typeGuardFunction.ts, 20, 3)) >B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) -// Basic. +// Basic if (isC(a)) { >isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39)) >a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) @@ -60,7 +60,7 @@ if (isC(a)) { >propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) } -// Sub type. +// Sub type var subType: C; >subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) @@ -75,7 +75,7 @@ if(isA(subType)) { >propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) } -// Union type. +// Union type var union: A | B; >union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) @@ -109,36 +109,85 @@ if (isC_multipleParams(a, 0)) { >propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19)) } +// Methods +var obj: { +>obj : Symbol(obj, Decl(typeGuardFunction.ts, 47, 3)) + + func1(p1: A): p1 is C; +>func1 : Symbol(func1, Decl(typeGuardFunction.ts, 47, 10)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 48, 10)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +} +class D { +>D : Symbol(D, Decl(typeGuardFunction.ts, 49, 1)) + + method1(p1: A): p1 is C { +>method1 : Symbol(method1, Decl(typeGuardFunction.ts, 50, 9)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 12)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + + return true; + } +} + +// Arrow function +let f1 = (p1: A): p1 is C => false; +>f1 : Symbol(f1, Decl(typeGuardFunction.ts, 57, 3)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 57, 10)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +// Function type +declare function f2(p1: (p1: A) => p1 is C); +>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 20)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 25)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + +// Function expressions +f2(function(p1: A): p1 is C { +>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 63, 12)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) + + return true; +}); + // Evaluations are asssignable to boolean. declare function acceptingBoolean(a: boolean); ->acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) ->a : Symbol(a, Decl(typeGuardFunction.ts, 47, 34)) +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 68, 34)) acceptingBoolean(isA(a)); ->acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1)) +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) >a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) // Type predicates with different parameter name. declare function acceptingTypeGuardFunction(p1: (item) => item is A); ->acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 44)) ->item : Symbol(item, Decl(typeGuardFunction.ts, 51, 49)) +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 72, 44)) +>item : Symbol(item, Decl(typeGuardFunction.ts, 72, 49)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) acceptingTypeGuardFunction(isA); ->acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25)) +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) +// Binary expressions let union2: C | B; ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) >B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) let union3: boolean | B = isA(union2) || union2; ->union3 : Symbol(union3, Decl(typeGuardFunction.ts, 55, 3)) +>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 77, 3)) >B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) diff --git a/tests/baselines/reference/typeGuardFunction.types b/tests/baselines/reference/typeGuardFunction.types index 2b3d1c40c8e..06e9be615e2 100644 --- a/tests/baselines/reference/typeGuardFunction.types +++ b/tests/baselines/reference/typeGuardFunction.types @@ -52,7 +52,7 @@ var b: B; >b : B >B : B -// Basic. +// Basic if (isC(a)) { >isC(a) : boolean >isC : (p1: any) => boolean @@ -64,7 +64,7 @@ if (isC(a)) { >propC : number } -// Sub type. +// Sub type var subType: C; >subType : C >C : C @@ -80,7 +80,7 @@ if(isA(subType)) { >propC : number } -// Union type. +// Union type var union: A | B; >union : A | B >A : A @@ -118,6 +118,66 @@ if (isC_multipleParams(a, 0)) { >propC : number } +// Methods +var obj: { +>obj : { func1(p1: A): boolean; } + + func1(p1: A): p1 is C; +>func1 : (p1: A) => boolean +>p1 : A +>A : A +>p1 : any +>C : C +} +class D { +>D : D + + method1(p1: A): p1 is C { +>method1 : (p1: A) => boolean +>p1 : A +>A : A +>p1 : any +>C : C + + return true; +>true : boolean + } +} + +// Arrow function +let f1 = (p1: A): p1 is C => false; +>f1 : (p1: A) => boolean +>(p1: A): p1 is C => false : (p1: A) => boolean +>p1 : A +>A : A +>p1 : any +>C : C +>false : boolean + +// Function type +declare function f2(p1: (p1: A) => p1 is C); +>f2 : (p1: (p1: A) => boolean) => any +>p1 : (p1: A) => boolean +>p1 : A +>A : A +>p1 : any +>C : C + +// Function expressions +f2(function(p1: A): p1 is C { +>f2(function(p1: A): p1 is C { return true;}) : any +>f2 : (p1: (p1: A) => boolean) => any +>function(p1: A): p1 is C { return true;} : (p1: A) => boolean +>p1 : A +>A : A +>p1 : any +>C : C + + return true; +>true : boolean + +}); + // Evaluations are asssignable to boolean. declare function acceptingBoolean(a: boolean); >acceptingBoolean : (a: boolean) => any @@ -143,6 +203,7 @@ acceptingTypeGuardFunction(isA); >acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any >isA : (p1: any) => boolean +// Binary expressions let union2: C | B; >union2 : B | C >C : C diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 0d5065395a9..bcef83601aa 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,5 +1,4 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Type predicates are only allowed in return type position. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected. @@ -22,12 +21,18 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1225: Cannot find parameter 'p1'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS1228: Type predicates are only allowed in return type position. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS1228: Type predicates are only allowed in return type position. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS1228: Type predicates are only allowed in return type position. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,25): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(109,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,16): error TS2408: Setters cannot return a value. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,20): error TS1229: Type predicate cannot reference a spread parameter. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (21 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (26 errors) ==== class A { propA: number; @@ -48,8 +53,6 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20) } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { - ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position. return true; } @@ -166,12 +169,42 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20) // Type predicates in non-return type positions var b1: b is A; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position. +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. function b2(a: b is A) {}; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position. +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. function b3(): A | b is A { ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position. +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. return true; - }; \ No newline at end of file + }; + + // Non-compatiable type predicate positions for signature declarations + class D { + constructor(p1: A): p1 is C { + ~~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. + return true; + ~~~~ +!!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class + } + get m1(p1: A): p1 is C { + ~~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. + return true; + } + set m2(p1: A): p1 is C { + ~~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. + return true; + ~~~~ +!!! error TS2408: Setters cannot return a value. + } + } + + // Reference to spread parameter + function b4(...a): a is A { + ~ +!!! error TS1229: Type predicate cannot reference a spread parameter. + return true; + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 0617cc1495a..2d3ccc561ed 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -97,7 +97,25 @@ var b1: b is A; function b2(a: b is A) {}; function b3(): A | b is A { return true; -}; +}; + +// Non-compatiable type predicate positions for signature declarations +class D { + constructor(p1: A): p1 is C { + return true; + } + get m1(p1: A): p1 is C { + return true; + } + set m2(p1: A): p1 is C { + return true; + } +} + +// Reference to spread parameter +function b4(...a): a is A { + return true; +} //// [typeGuardFunctionErrors.js] var __extends = (this && this.__extends) || function (d, b) { @@ -183,3 +201,32 @@ function b3() { return true; } ; +// Non-compatiable type predicate positions for signature declarations +var D = (function () { + function D(p1) { + return true; + } + Object.defineProperty(D.prototype, "m1", { + get: function (p1) { + return true; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(D.prototype, "m2", { + set: function (p1) { + return true; + }, + enumerable: true, + configurable: true + }); + return D; +})(); +// Reference to spread parameter +function b4() { + var a = []; + for (var _i = 0; _i < arguments.length; _i++) { + a[_i - 0] = arguments[_i]; + } + return true; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts index 93cfd90ceb5..316a1483380 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts @@ -20,18 +20,18 @@ declare function retC(): C; var a: A; var b: B; -// Basic. +// Basic if (isC(a)) { a.propC; } -// Sub type. +// Sub type var subType: C; if(isA(subType)) { subType.propC; } -// Union type. +// Union type var union: A | B; if(isA(union)) { union.propA; @@ -44,6 +44,27 @@ if (isC_multipleParams(a, 0)) { a.propC; } +// Methods +var obj: { + func1(p1: A): p1 is C; +} +class D { + method1(p1: A): p1 is C { + return true; + } +} + +// Arrow function +let f1 = (p1: A): p1 is C => false; + +// Function type +declare function f2(p1: (p1: A) => p1 is C); + +// Function expressions +f2(function(p1: A): p1 is C { + return true; +}); + // Evaluations are asssignable to boolean. declare function acceptingBoolean(a: boolean); acceptingBoolean(isA(a)); @@ -52,5 +73,6 @@ acceptingBoolean(isA(a)); declare function acceptingTypeGuardFunction(p1: (item) => item is A); acceptingTypeGuardFunction(isA); +// Binary expressions let union2: C | B; let union3: boolean | B = isA(union2) || union2; \ No newline at end of file diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts index baae822ec2d..df1d0b974c4 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -96,4 +96,22 @@ var b1: b is A; function b2(a: b is A) {}; function b3(): A | b is A { return true; -}; \ No newline at end of file +}; + +// Non-compatiable type predicate positions for signature declarations +class D { + constructor(p1: A): p1 is C { + return true; + } + get m1(p1: A): p1 is C { + return true; + } + set m2(p1: A): p1 is C { + return true; + } +} + +// Reference to spread parameter +function b4(...a): a is A { + return true; +} \ No newline at end of file From e75204bc868ceddb44b9c0d9304e11c20fbeda67 Mon Sep 17 00:00:00 2001 From: SaschaNaz Date: Sat, 6 Jun 2015 20:25:01 +0900 Subject: [PATCH 25/40] Removing lib.dom.es6.d.ts line --- Jakefile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Jakefile.js b/Jakefile.js index 1d6984a1782..9b95744d392 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -145,7 +145,6 @@ var harnessSources = [ var librarySourceMap = [ { target: "lib.core.d.ts", sources: ["core.d.ts"] }, { target: "lib.dom.d.ts", sources: ["importcore.d.ts", "extensions.d.ts", "intl.d.ts", "dom.generated.d.ts"], }, - { target: "lib.dom.es6.d.ts", sources: ["importcore.d.ts", "es6.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts"] }, { target: "lib.webworker.d.ts", sources: ["importcore.d.ts", "extensions.d.ts", "intl.d.ts", "webworker.generated.d.ts"], }, { target: "lib.scriptHost.d.ts", sources: ["importcore.d.ts", "scriptHost.d.ts"], }, { target: "lib.d.ts", sources: ["core.d.ts", "extensions.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"], }, From b82ae8509cde788bb8e3329932942c3d179a5ade Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Jun 2015 11:45:21 -0700 Subject: [PATCH 26/40] Addressing CR feedback --- src/compiler/checker.ts | 74 +++++++++++++++++++++++------------------ src/compiler/types.ts | 4 +-- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 40e98b44148..965fbbfb9c0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1789,7 +1789,7 @@ module ts { function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags) { let targetSymbol = getTargetSymbol(symbol); if (targetSymbol.flags & SymbolFlags.Class || targetSymbol.flags & SymbolFlags.Interface) { - buildDisplayForTypeParametersAndDelimiters(getLocalTypeParametersOfClassOrInterface(symbol), writer, enclosingDeclaraiton, flags); + buildDisplayForTypeParametersAndDelimiters(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), writer, enclosingDeclaraiton, flags); } } @@ -2573,8 +2573,9 @@ module ts { return appendOuterTypeParameters(undefined, getDeclarationOfKind(symbol, kind)); } - // The local type parameters are the combined set of type parameters from all declarations of the class or interface. - function getLocalTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] { + // The local type parameters are the combined set of type parameters from all declarations of the class, + // interface, or type alias. + function getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): TypeParameter[] { let result: TypeParameter[]; for (let node of symbol.declarations) { if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.TypeAliasDeclaration) { @@ -2590,16 +2591,7 @@ module ts { // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus // its locally declared type parameters. function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] { - return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterface(symbol)); - } - - function getTypeParametersOfTypeAlias(symbol: Symbol): TypeParameter[] { - let links = getSymbolLinks(symbol); - if (!links.typeParameters) { - let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); - links.typeParameters = declaration.typeParameters ? appendTypeParameters(undefined, declaration.typeParameters) : emptyArray; - } - return links.typeParameters; + return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)); } function getBaseTypes(type: InterfaceType): ObjectType[] { @@ -2672,7 +2664,7 @@ module ts { let kind = symbol.flags & SymbolFlags.Class ? TypeFlags.Class : TypeFlags.Interface; let type = links.declaredType = createObjectType(kind, symbol); let outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol); - let localTypeParameters = getLocalTypeParametersOfClassOrInterface(symbol); + let localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (outerTypeParameters || localTypeParameters) { type.flags |= TypeFlags.Reference; type.typeParameters = concatenate(outerTypeParameters, localTypeParameters); @@ -2697,7 +2689,16 @@ module ts { } let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); let type = getTypeFromTypeNode(declaration.type); - if (!popTypeResolution()) { + if (popTypeResolution()) { + links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + if (links.typeParameters) { + // Initialize the instantiation cache for generic type aliases. The declared type corresponds to + // an instantiation of the type alias with the type parameters supplied as type arguments. + links.instantiations = {}; + links.instantiations[getTypeListId(links.typeParameters)] = type; + } + } + else { type = unknownType; error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); } @@ -3522,6 +3523,7 @@ module ts { } } + // Get type from reference to class or interface function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { let type = getDeclaredTypeOfSymbol(symbol); let typeParameters = (type).localTypeParameters; @@ -3543,22 +3545,20 @@ module ts { return type; } + // Get type from reference to type alias. When a type alias is generic, the declared type of the type alias may include + // references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the + // declared type. Instantiations are cached using the type identities of the type arguments as the key. function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { let type = getDeclaredTypeOfSymbol(symbol); - let typeParameters = getTypeParametersOfTypeAlias(symbol); - if (typeParameters.length) { + let links = getSymbolLinks(symbol); + let typeParameters = links.typeParameters; + if (typeParameters) { if (!node.typeArguments || node.typeArguments.length !== typeParameters.length) { error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, symbolToString(symbol), typeParameters.length); return unknownType; } let typeArguments = map(node.typeArguments, getTypeFromTypeNode); let id = getTypeListId(typeArguments); - let links = getSymbolLinks(symbol); - if (!links.instantiations) { - links.instantiations = {}; - // The declared type corresponds to an instantiation with its own type parameters as type arguments - links.instantiations[getTypeListId(typeParameters)] = type; - } return links.instantiations[id] || (links.instantiations[id] = instantiateType(type, createTypeMapper(typeParameters, typeArguments))); } if (node.typeArguments) { @@ -3568,12 +3568,20 @@ module ts { return type; } - function getTypeFromTypeParameterReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { - // TypeScript 1.0 spec (April 2014): 3.4.1 - // Type parameters declared in a particular type parameter list - // may not be referenced in constraints in that type parameter list - // Implementation: such type references are resolved to 'unknown' type that usually denotes error - return isTypeParameterReferenceIllegalInConstraint(node, symbol) ? unknownType : getDeclaredTypeOfSymbol(symbol); + // Get type from reference to named type that cannot be generic (enum or type parameter) + function getTypeFromNonGenericTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments, symbol: Symbol): Type { + if (symbol.flags & SymbolFlags.TypeParameter && isTypeParameterReferenceIllegalInConstraint(node, symbol)) { + // TypeScript 1.0 spec (April 2014): 3.4.1 + // Type parameters declared in a particular type parameter list + // may not be referenced in constraints in that type parameter list + // Implementation: such type references are resolved to 'unknown' type that usually denotes error + return unknownType; + } + if (node.typeArguments) { + error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol)); + return unknownType; + } + return getDeclaredTypeOfSymbol(symbol); } function getTypeFromTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments): Type { @@ -3583,10 +3591,10 @@ module ts { isSupportedExpressionWithTypeArguments(node) ? (node).expression : undefined; let symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; - let type = symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) : - symbol.flags & SymbolFlags.TypeParameter ? getTypeFromTypeParameterReference(node, symbol) : + let type = symbol === unknownSymbol ? unknownType : + symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) : symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) : - getDeclaredTypeOfSymbol(symbol); + getTypeFromNonGenericTypeReference(node, symbol); // Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the // type reference in checkTypeReferenceOrExpressionWithTypeArguments. links.resolvedSymbol = symbol; @@ -8786,7 +8794,7 @@ module ts { if (type !== unknownType && node.typeArguments) { // Do type argument local checks only if referenced type is successfully resolved let symbol = getNodeLinks(node).resolvedSymbol; - let typeParameters = symbol.flags & SymbolFlags.TypeAlias ? getTypeParametersOfTypeAlias(symbol) : (type).target.localTypeParameters; + let typeParameters = symbol.flags & SymbolFlags.TypeAlias ? getSymbolLinks(symbol).typeParameters : (type).target.localTypeParameters; let len = node.typeArguments.length; for (let i = 0; i < len; i++) { checkSourceElement(node.typeArguments[i]); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4f37869b5bf..723073e1b18 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1527,8 +1527,8 @@ module ts { target?: Symbol; // Resolved (non-alias) target of an alias type?: Type; // Type of value symbol declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter - typeParameters?: TypeParameter[]; // Type parameters of type alias (empty array if none) - instantiations?: Map; // Instantiations of generic type alias + typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic) + 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 From 33517c463514c97eebcedabf9f3417966243acb7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Jun 2015 17:47:22 -0700 Subject: [PATCH 27/40] Adding test as suggested in CR feedback --- ...cTypeReferenceWithTypeArguments.errors.txt | 34 ++++++++++++++++++ ...onGenericTypeReferenceWithTypeArguments.js | 35 +++++++++++++++++++ ...onGenericTypeReferenceWithTypeArguments.ts | 15 ++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt create mode 100644 tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js create mode 100644 tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts diff --git a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt new file mode 100644 index 00000000000..7ed41b52489 --- /dev/null +++ b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt @@ -0,0 +1,34 @@ +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(8,9): error TS2315: Type 'C' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(9,9): error TS2315: Type 'I' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(10,9): error TS2315: Type 'E' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(11,9): error TS2315: Type 'T' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(14,12): error TS2315: Type 'U' is not generic. + + +==== tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts (5 errors) ==== + // Check that errors are reported for non-generic types with type arguments + + class C { } + interface I { } + enum E { } + type T = { }; + + var v1: C; + ~~~~~~~~~ +!!! error TS2315: Type 'C' is not generic. + var v2: I; + ~~~~~~~~~ +!!! error TS2315: Type 'I' is not generic. + var v3: E; + ~~~~~~~~~ +!!! error TS2315: Type 'E' is not generic. + var v4: T; + ~~~~~~~~~ +!!! error TS2315: Type 'T' is not generic. + + function f() { + var x: U; + ~~~~~~~~~ +!!! error TS2315: Type 'U' is not generic. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js new file mode 100644 index 00000000000..798a660e326 --- /dev/null +++ b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js @@ -0,0 +1,35 @@ +//// [nonGenericTypeReferenceWithTypeArguments.ts] +// Check that errors are reported for non-generic types with type arguments + +class C { } +interface I { } +enum E { } +type T = { }; + +var v1: C; +var v2: I; +var v3: E; +var v4: T; + +function f() { + var x: U; +} + + +//// [nonGenericTypeReferenceWithTypeArguments.js] +// Check that errors are reported for non-generic types with type arguments +var C = (function () { + function C() { + } + return C; +})(); +var E; +(function (E) { +})(E || (E = {})); +var v1; +var v2; +var v3; +var v4; +function f() { + var x; +} diff --git a/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts b/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts new file mode 100644 index 00000000000..01679367177 --- /dev/null +++ b/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts @@ -0,0 +1,15 @@ +// Check that errors are reported for non-generic types with type arguments + +class C { } +interface I { } +enum E { } +type T = { }; + +var v1: C; +var v2: I; +var v3: E; +var v4: T; + +function f() { + var x: U; +} From 7c2a3c256d8449401d1611f38423d273e5407577 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Jun 2015 17:54:11 -0700 Subject: [PATCH 28/40] Modifying test a bit --- ...cTypeReferenceWithTypeArguments.errors.txt | 37 ++++++++++++++----- ...onGenericTypeReferenceWithTypeArguments.js | 25 +++++++++++-- ...onGenericTypeReferenceWithTypeArguments.ts | 11 +++++- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt index 7ed41b52489..b227ff0f0ae 100644 --- a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt +++ b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.errors.txt @@ -1,18 +1,21 @@ -tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(8,9): error TS2315: Type 'C' is not generic. -tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(9,9): error TS2315: Type 'I' is not generic. -tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(10,9): error TS2315: Type 'E' is not generic. -tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(11,9): error TS2315: Type 'T' is not generic. -tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(14,12): error TS2315: Type 'U' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(7,9): error TS2315: Type 'C' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(8,9): error TS2315: Type 'I' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(9,9): error TS2315: Type 'E' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(10,9): error TS2315: Type 'T' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(17,13): error TS2315: Type 'C' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(18,13): error TS2315: Type 'I' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(19,13): error TS2315: Type 'E' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(20,13): error TS2315: Type 'T' is not generic. +tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts(21,13): error TS2315: Type 'U' is not generic. -==== tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts (5 errors) ==== +==== tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts (9 errors) ==== // Check that errors are reported for non-generic types with type arguments class C { } interface I { } enum E { } type T = { }; - var v1: C; ~~~~~~~~~ !!! error TS2315: Type 'C' is not generic. @@ -27,8 +30,24 @@ tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeRefer !!! error TS2315: Type 'T' is not generic. function f() { - var x: U; - ~~~~~~~~~ + class C { } + interface I { } + enum E { } + type T = {}; + var v1: C; + ~~~~~~~~~ +!!! error TS2315: Type 'C' is not generic. + var v2: I; + ~~~~~~~~~ +!!! error TS2315: Type 'I' is not generic. + var v3: E; + ~~~~~~~~~ +!!! error TS2315: Type 'E' is not generic. + var v4: T; + ~~~~~~~~~ +!!! error TS2315: Type 'T' is not generic. + var v5: U; + ~~~~~~~~~ !!! error TS2315: Type 'U' is not generic. } \ No newline at end of file diff --git a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js index 798a660e326..5558cb2fc8b 100644 --- a/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js +++ b/tests/baselines/reference/nonGenericTypeReferenceWithTypeArguments.js @@ -5,14 +5,21 @@ class C { } interface I { } enum E { } type T = { }; - var v1: C; var v2: I; var v3: E; var v4: T; function f() { - var x: U; + class C { } + interface I { } + enum E { } + type T = {}; + var v1: C; + var v2: I; + var v3: E; + var v4: T; + var v5: U; } @@ -31,5 +38,17 @@ var v2; var v3; var v4; function f() { - var x; + var C = (function () { + function C() { + } + return C; + })(); + var E; + (function (E) { + })(E || (E = {})); + var v1; + var v2; + var v3; + var v4; + var v5; } diff --git a/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts b/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts index 01679367177..0d84fe7ae51 100644 --- a/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts +++ b/tests/cases/conformance/types/specifyingTypes/typeReferences/nonGenericTypeReferenceWithTypeArguments.ts @@ -4,12 +4,19 @@ class C { } interface I { } enum E { } type T = { }; - var v1: C; var v2: I; var v3: E; var v4: T; function f() { - var x: U; + class C { } + interface I { } + enum E { } + type T = {}; + var v1: C; + var v2: I; + var v3: E; + var v4: T; + var v5: U; } From b1a8a5fe664fbe96a0c0bbad3c4003aa13958407 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sun, 7 Jun 2015 18:31:53 +0800 Subject: [PATCH 29/40] Addresses CR feedback --- src/compiler/checker.ts | 41 ++++++++--- .../diagnosticInformationMap.generated.ts | 5 +- src/compiler/diagnosticMessages.json | 8 ++- .../baselines/reference/typeGuardFunction.js | 5 ++ .../reference/typeGuardFunction.symbols | 66 +++++++++-------- .../reference/typeGuardFunction.types | 11 +++ .../typeGuardFunctionErrors.errors.txt | 71 ++++++++++++------- .../reference/typeGuardFunctionErrors.js | 33 +++++++-- .../typeGuards/typeGuardFunction.ts | 5 ++ .../typeGuards/typeGuardFunctionErrors.ts | 22 ++++-- 10 files changed, 192 insertions(+), 75 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c7ccb98f8f2..720a2352b4f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8601,15 +8601,16 @@ module ts { } } - function isInATypePredicateCompatiblePosition(node: Node): boolean { + function isInLegalTypePredicatePosition(node: Node): boolean { switch (node.parent.kind) { case SyntaxKind.ArrowFunction: + case SyntaxKind.CallSignature: case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionType: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return true; + return node === (node.parent).type; } return false; } @@ -8634,11 +8635,11 @@ module ts { if (node.type.kind === SyntaxKind.TypePredicate) { let typePredicate = getSignatureFromDeclaration(node).typePredicate; let typePredicateNode = node.type; - if (isInATypePredicateCompatiblePosition(typePredicateNode)) { + if (isInLegalTypePredicatePosition(typePredicateNode)) { if (typePredicate.parameterIndex >= 0) { if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) { error(typePredicateNode.parameterName, - Diagnostics.Type_predicate_cannot_reference_a_spread_parameter); + Diagnostics.Type_predicate_cannot_reference_a_rest_parameter); } else { checkTypeAssignableTo(typePredicate.type, @@ -8647,14 +8648,34 @@ module ts { } } else if (typePredicateNode.parameterName) { - error(typePredicateNode.parameterName, - Diagnostics.Cannot_find_parameter_0, - typePredicate.parameterName); + let hasReportedError = false; + outer: for (let param of node.parameters) { + if (param.name.kind === SyntaxKind.ObjectBindingPattern || + param.name.kind === SyntaxKind.ArrayBindingPattern) { + + for (let element of (param.name).elements) { + if (element.name.kind === SyntaxKind.Identifier && + (element.name).text === typePredicateNode.parameterName.text) { + + error(typePredicateNode.parameterName, + Diagnostics.Type_predicate_cannot_reference_element_0_in_a_binding_pattern, + typePredicate.parameterName); + hasReportedError = true; + break outer; + } + } + } + } + if (!hasReportedError) { + error(typePredicateNode.parameterName, + Diagnostics.Cannot_find_parameter_0, + typePredicate.parameterName); + } } } else { error(typePredicateNode, - Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations); + Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods); } } else { @@ -11295,8 +11316,8 @@ module ts { } function checkTypePredicate(node: TypePredicateNode) { - if(!isInATypePredicateCompatiblePosition(node)) { - error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations); + if(!isInLegalTypePredicatePosition(node)) { + error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 25d3730cc07..96480f17ac3 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -183,8 +183,9 @@ module ts { Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations." }, - Type_predicate_cannot_reference_a_spread_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a spread parameter." }, + Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for functions and methods." }, + Type_predicate_cannot_reference_a_rest_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a rest parameter." }, + Type_predicate_cannot_reference_element_0_in_a_binding_pattern: { code: 1230, category: DiagnosticCategory.Error, key: "Type predicate cannot reference element '{0}' in a binding pattern." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4008a6af1b1..64b9c93fd60 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -719,14 +719,18 @@ "category": "Error", "code": 1227 }, - "Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations.": { + "Type predicates are only allowed in return type position for functions and methods.": { "category": "Error", "code": 1228 }, - "Type predicate cannot reference a spread parameter.": { + "Type predicate cannot reference a rest parameter.": { "category": "Error", "code": 1229 }, + "Type predicate cannot reference element '{0}' in a binding pattern.": { + "category": "Error", + "code": 1230 + }, "Duplicate identifier '{0}'.": { diff --git a/tests/baselines/reference/typeGuardFunction.js b/tests/baselines/reference/typeGuardFunction.js index 5c256160bba..f6b752c8c04 100644 --- a/tests/baselines/reference/typeGuardFunction.js +++ b/tests/baselines/reference/typeGuardFunction.js @@ -38,6 +38,11 @@ if(isA(union)) { union.propA; } +// Call signature +interface I1 { + (p1: A): p1 is C; +} + // The parameter index and argument index for the type guard target is matching. // The type predicate type is assignable to the parameter type. declare function isC_multipleParams(p1, p2): p1 is C; diff --git a/tests/baselines/reference/typeGuardFunction.symbols b/tests/baselines/reference/typeGuardFunction.symbols index 5b5fe1ec855..c315e721085 100644 --- a/tests/baselines/reference/typeGuardFunction.symbols +++ b/tests/baselines/reference/typeGuardFunction.symbols @@ -91,16 +91,26 @@ if(isA(union)) { >propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9)) } +// Call signature +interface I1 { +>I1 : Symbol(I1, Decl(typeGuardFunction.ts, 37, 1)) + + (p1: A): p1 is C; +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 5)) +>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) +>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) +} + // The parameter index and argument index for the type guard target is matching. // The type predicate type is assignable to the parameter type. declare function isC_multipleParams(p1, p2): p1 is C; ->isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 36)) ->p2 : Symbol(p2, Decl(typeGuardFunction.ts, 41, 39)) +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 42, 1)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 46, 36)) +>p2 : Symbol(p2, Decl(typeGuardFunction.ts, 46, 39)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) if (isC_multipleParams(a, 0)) { ->isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1)) +>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 42, 1)) >a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) a.propC; @@ -111,20 +121,20 @@ if (isC_multipleParams(a, 0)) { // Methods var obj: { ->obj : Symbol(obj, Decl(typeGuardFunction.ts, 47, 3)) +>obj : Symbol(obj, Decl(typeGuardFunction.ts, 52, 3)) func1(p1: A): p1 is C; ->func1 : Symbol(func1, Decl(typeGuardFunction.ts, 47, 10)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 48, 10)) +>func1 : Symbol(func1, Decl(typeGuardFunction.ts, 52, 10)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 53, 10)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) } class D { ->D : Symbol(D, Decl(typeGuardFunction.ts, 49, 1)) +>D : Symbol(D, Decl(typeGuardFunction.ts, 54, 1)) method1(p1: A): p1 is C { ->method1 : Symbol(method1, Decl(typeGuardFunction.ts, 50, 9)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 12)) +>method1 : Symbol(method1, Decl(typeGuardFunction.ts, 55, 9)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 56, 12)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) @@ -134,23 +144,23 @@ class D { // Arrow function let f1 = (p1: A): p1 is C => false; ->f1 : Symbol(f1, Decl(typeGuardFunction.ts, 57, 3)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 57, 10)) +>f1 : Symbol(f1, Decl(typeGuardFunction.ts, 62, 3)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 62, 10)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) // Function type declare function f2(p1: (p1: A) => p1 is C); ->f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 20)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 25)) +>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 62, 35)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 65, 20)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 65, 25)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) // Function expressions f2(function(p1: A): p1 is C { ->f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 63, 12)) +>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 62, 35)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 68, 12)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) @@ -159,35 +169,35 @@ f2(function(p1: A): p1 is C { // Evaluations are asssignable to boolean. declare function acceptingBoolean(a: boolean); ->acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3)) ->a : Symbol(a, Decl(typeGuardFunction.ts, 68, 34)) +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 70, 3)) +>a : Symbol(a, Decl(typeGuardFunction.ts, 73, 34)) acceptingBoolean(isA(a)); ->acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3)) +>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 70, 3)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) >a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3)) // Type predicates with different parameter name. declare function acceptingTypeGuardFunction(p1: (item) => item is A); ->acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25)) ->p1 : Symbol(p1, Decl(typeGuardFunction.ts, 72, 44)) ->item : Symbol(item, Decl(typeGuardFunction.ts, 72, 49)) +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 74, 25)) +>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 77, 44)) +>item : Symbol(item, Decl(typeGuardFunction.ts, 77, 49)) >A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0)) acceptingTypeGuardFunction(isA); ->acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25)) +>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 74, 25)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) // Binary expressions let union2: C | B; ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 3)) >C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1)) >B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) let union3: boolean | B = isA(union2) || union2; ->union3 : Symbol(union3, Decl(typeGuardFunction.ts, 77, 3)) +>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 82, 3)) >B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1)) >isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1)) ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) ->union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 3)) +>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 3)) diff --git a/tests/baselines/reference/typeGuardFunction.types b/tests/baselines/reference/typeGuardFunction.types index 06e9be615e2..cf673f965f9 100644 --- a/tests/baselines/reference/typeGuardFunction.types +++ b/tests/baselines/reference/typeGuardFunction.types @@ -97,6 +97,17 @@ if(isA(union)) { >propA : number } +// Call signature +interface I1 { +>I1 : I1 + + (p1: A): p1 is C; +>p1 : A +>A : A +>p1 : any +>C : C +} + // The parameter index and argument index for the type guard target is matching. // The type predicate type is assignable to the parameter type. declare function isC_multipleParams(p1, p2): p1 is C; diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index bcef83601aa..337dcd317c9 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -20,19 +20,22 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1225: Cannot find parameter 'p1'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,25): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(109,20): error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,16): error TS2408: Setters cannot return a value. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,20): error TS1229: Type predicate cannot reference a spread parameter. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,9): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,16): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(94,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(101,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,16): error TS2408: Setters cannot return a value. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,18): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,22): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,20): error TS1229: Type predicate cannot reference a rest parameter. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(125,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (26 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (29 errors) ==== class A { propA: number; @@ -161,21 +164,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,20 return true; }; - // Type guard paramater referring to a binding pattern - declare function destructureParameter({ p1, p2, p3 }): p1 is A; - ~~ -!!! error TS1225: Cannot find parameter 'p1'. - // Type predicates in non-return type positions var b1: b is A; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. function b2(a: b is A) {}; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. function b3(): A | b is A { ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. return true; }; @@ -183,28 +181,53 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,20 class D { constructor(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. return true; } set m2(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations. +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2408: Setters cannot return a value. } } - // Reference to spread parameter + interface I1 { + new (p1: A): p1 is C; + ~~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. + } + + interface I2 { + [index: number]: p1 is C; + ~~~~~~~ +!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. + } + + // Reference to rest parameter function b4(...a): a is A { ~ -!!! error TS1229: Type predicate cannot reference a spread parameter. +!!! error TS1229: Type predicate cannot reference a rest parameter. + return true; + } + + // Reference to binding pattern + function b5({a, b, p1}, p2, p3): p1 is A { + ~~ +!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. + return true; + } + + function b6([a, b, p1], p2, p3): p1 is A { + ~~ +!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. return true; } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 2d3ccc561ed..354aae2f2a1 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -89,9 +89,6 @@ assign3 = function(p1, p2, p3): p1 is A { return true; }; -// Type guard paramater referring to a binding pattern -declare function destructureParameter({ p1, p2, p3 }): p1 is A; - // Type predicates in non-return type positions var b1: b is A; function b2(a: b is A) {}; @@ -112,9 +109,26 @@ class D { } } -// Reference to spread parameter +interface I1 { + new (p1: A): p1 is C; +} + +interface I2 { + [index: number]: p1 is C; +} + +// Reference to rest parameter function b4(...a): a is A { return true; +} + +// Reference to binding pattern +function b5({a, b, p1}, p2, p3): p1 is A { + return true; +} + +function b6([a, b, p1], p2, p3): p1 is A { + return true; } //// [typeGuardFunctionErrors.js] @@ -222,7 +236,7 @@ var D = (function () { }); return D; })(); -// Reference to spread parameter +// Reference to rest parameter function b4() { var a = []; for (var _i = 0; _i < arguments.length; _i++) { @@ -230,3 +244,12 @@ function b4() { } return true; } +// Reference to binding pattern +function b5(_a, p2, p3) { + var a = _a.a, b = _a.b, p1 = _a.p1; + return true; +} +function b6(_a, p2, p3) { + var a = _a[0], b = _a[1], p1 = _a[2]; + return true; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts index 316a1483380..57d56ccc3b6 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunction.ts @@ -37,6 +37,11 @@ if(isA(union)) { union.propA; } +// Call signature +interface I1 { + (p1: A): p1 is C; +} + // The parameter index and argument index for the type guard target is matching. // The type predicate type is assignable to the parameter type. declare function isC_multipleParams(p1, p2): p1 is C; diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts index df1d0b974c4..e7012a172b0 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -88,9 +88,6 @@ assign3 = function(p1, p2, p3): p1 is A { return true; }; -// Type guard paramater referring to a binding pattern -declare function destructureParameter({ p1, p2, p3 }): p1 is A; - // Type predicates in non-return type positions var b1: b is A; function b2(a: b is A) {}; @@ -111,7 +108,24 @@ class D { } } -// Reference to spread parameter +interface I1 { + new (p1: A): p1 is C; +} + +interface I2 { + [index: number]: p1 is C; +} + +// Reference to rest parameter function b4(...a): a is A { return true; +} + +// Reference to binding pattern +function b5({a, b, p1}, p2, p3): p1 is A { + return true; +} + +function b6([a, b, p1], p2, p3): p1 is A { + return true; } \ No newline at end of file From 51a43dd9d5e3e007d6b8e5e63d24d24a35cd86d7 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Mon, 8 Jun 2015 11:41:08 +0800 Subject: [PATCH 30/40] Addresses CR feedback --- bin/tsc | 0 src/compiler/checker.ts | 38 ++++++++++------- .../diagnosticInformationMap.generated.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- .../typeGuardFunctionErrors.errors.txt | 41 +++++++++++-------- .../reference/typeGuardFunctionErrors.js | 8 ++++ .../typeGuards/typeGuardFunctionErrors.ts | 4 ++ 7 files changed, 62 insertions(+), 33 deletions(-) mode change 100644 => 100755 bin/tsc diff --git a/bin/tsc b/bin/tsc old mode 100644 new mode 100755 diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 720a2352b4f..4514834a9ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8649,21 +8649,31 @@ module ts { } else if (typePredicateNode.parameterName) { let hasReportedError = false; - outer: for (let param of node.parameters) { + for (var param of node.parameters) { + if (hasReportedError) { + break; + } if (param.name.kind === SyntaxKind.ObjectBindingPattern || param.name.kind === SyntaxKind.ArrayBindingPattern) { - - for (let element of (param.name).elements) { - if (element.name.kind === SyntaxKind.Identifier && - (element.name).text === typePredicateNode.parameterName.text) { - - error(typePredicateNode.parameterName, - Diagnostics.Type_predicate_cannot_reference_element_0_in_a_binding_pattern, - typePredicate.parameterName); - hasReportedError = true; - break outer; + + (function checkBindingPattern(elements: NodeArray) { + for (let element of elements) { + if (element.name.kind === SyntaxKind.Identifier && + (element.name).text === typePredicate.parameterName) { + + error(typePredicateNode.parameterName, + Diagnostics.Type_predicate_cannot_reference_element_0_in_a_binding_pattern, + typePredicate.parameterName); + hasReportedError = true; + break; + } + else if(element.name.kind === SyntaxKind.ArrayBindingPattern || + element.name.kind === SyntaxKind.ObjectBindingPattern) { + + checkBindingPattern((element.name).elements); + } } - } + })((param.name).elements); } } if (!hasReportedError) { @@ -8675,7 +8685,7 @@ module ts { } else { error(typePredicateNode, - Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods); + Diagnostics.Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods); } } else { @@ -11317,7 +11327,7 @@ module ts { function checkTypePredicate(node: TypePredicateNode) { if(!isInLegalTypePredicatePosition(node)) { - error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods); + error(node, Diagnostics.Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 96480f17ac3..1a79f4b2f44 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -183,7 +183,7 @@ module ts { Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for functions and methods." }, + Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicate are only allowed in return type position for functions and methods." }, Type_predicate_cannot_reference_a_rest_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a rest parameter." }, Type_predicate_cannot_reference_element_0_in_a_binding_pattern: { code: 1230, category: DiagnosticCategory.Error, key: "Type predicate cannot reference element '{0}' in a binding pattern." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 64b9c93fd60..6ffc62a66ee 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -719,7 +719,7 @@ "category": "Error", "code": 1227 }, - "Type predicates are only allowed in return type position for functions and methods.": { + "Type predicate are only allowed in return type position for functions and methods.": { "category": "Error", "code": 1228 }, diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 337dcd317c9..7fa26b41217 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -20,22 +20,23 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,9): error TS1228: Type predicates are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,16): error TS1228: Type predicates are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(94,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,9): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,16): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(94,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1228: Type predicate are only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(101,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,16): error TS2408: Setters cannot return a value. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,18): error TS1228: Type predicates are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,22): error TS1228: Type predicates are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,18): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,22): error TS1228: Type predicate are only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,20): error TS1229: Type predicate cannot reference a rest parameter. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(125,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (29 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (30 errors) ==== class A { propA: number; @@ -167,13 +168,13 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34 // Type predicates in non-return type positions var b1: b is A; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. function b2(a: b is A) {}; ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. function b3(): A | b is A { ~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. return true; }; @@ -181,19 +182,19 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34 class D { constructor(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. return true; } set m2(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2408: Setters cannot return a value. @@ -203,13 +204,13 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34 interface I1 { new (p1: A): p1 is C; ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. } interface I2 { [index: number]: p1 is C; ~~~~~~~ -!!! error TS1228: Type predicates are only allowed in return type position for functions and methods. +!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. } // Reference to rest parameter @@ -228,6 +229,12 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34 function b6([a, b, p1], p2, p3): p1 is A { ~~ +!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. + return true; + } + + function b7({a, b, c: {p1}}, p2, p3): p1 is A { + ~~ !!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. return true; } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 354aae2f2a1..179a3b80cf0 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -129,6 +129,10 @@ function b5({a, b, p1}, p2, p3): p1 is A { function b6([a, b, p1], p2, p3): p1 is A { return true; +} + +function b7({a, b, c: {p1}}, p2, p3): p1 is A { + return true; } //// [typeGuardFunctionErrors.js] @@ -253,3 +257,7 @@ function b6(_a, p2, p3) { var a = _a[0], b = _a[1], p1 = _a[2]; return true; } +function b7(_a, p2, p3) { + var a = _a.a, b = _a.b, p1 = _a.c.p1; + return true; +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts index e7012a172b0..e157b2afe36 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts @@ -128,4 +128,8 @@ function b5({a, b, p1}, p2, p3): p1 is A { function b6([a, b, p1], p2, p3): p1 is A { return true; +} + +function b7({a, b, c: {p1}}, p2, p3): p1 is A { + return true; } \ No newline at end of file From c96eee00efdb3e6a838abd3913ad4829b5f922c7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 8 Jun 2015 12:56:33 -0700 Subject: [PATCH 31/40] Adding a few comments per CR feedback --- src/compiler/binder.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9f7f36d10d0..a0e177e7659 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -386,10 +386,10 @@ module ts { function declareSymbolAndAddToSymbolTableWorker(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { switch (container.kind) { - // Modules, source files, and classes need specialized handling for how their + // Modules, source files, and classes need specialized handling for how their // members are declared (for example, a member of a class will go into a specific - // symbol table depending on if it is static or not). As such, we defer to - // specialized handlers to take care of declaring these child members. + // symbol table depending on if it is static or not). We defer to specialized + // handlers to take care of declaring these child members. case SyntaxKind.ModuleDeclaration: return declareModuleMember(node, symbolFlags, symbolExcludes); @@ -407,9 +407,10 @@ module ts { case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.InterfaceDeclaration: // Interface/Object-types always have their children added to the 'members' of - // their container. They are only accessible through an instance of their - // container, and are never in scope otherwise (even inside the body of the - // object / type / interface declaring them). + // their container. They are only accessible through an instance of their + // container, and are never in scope otherwise (even inside the body of the + // object / type / interface declaring them). An exception is type parameters, + // which are in scope without qualification (similar to 'locals'). return declareSymbol(container.symbol.members, container.symbol, node, symbolFlags, symbolExcludes); case SyntaxKind.FunctionType: @@ -427,10 +428,10 @@ module ts { case SyntaxKind.ArrowFunction: case SyntaxKind.TypeAliasDeclaration: // All the children of these container types are never visible through another - // symbol (i.e. through another symbol's 'exports' or 'members'). Instead, - // they're only accessed 'lexically' (i.e. from code that exists underneath + // symbol (i.e. through another symbol's 'exports' or 'members'). Instead, + // they're only accessed 'lexically' (i.e. from code that exists underneath // their container in the tree. To accomplish this, we simply add their declared - // symbol to the 'locals' of the container. These symbols can then be found as + // symbol to the 'locals' of the container. These symbols can then be found as // the type checker walks up the containers, checking them for matching names. return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes); } From ebe755b1865d82de7094943f771105d540cc0047 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 9 Jun 2015 07:32:03 +0800 Subject: [PATCH 32/40] Addresses CR feedback --- src/compiler/checker.ts | 20 ++++---- .../diagnosticInformationMap.generated.ts | 6 +-- src/compiler/diagnosticMessages.json | 6 +-- .../typeGuardFunctionErrors.errors.txt | 48 +++++++++---------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4514834a9ff..af1e9349eee 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8588,7 +8588,6 @@ module ts { } function getTypePredicateParameterIndex(parameterList: NodeArray, parameter: Identifier): number { - let index = -1; if (parameterList) { for (let i = 0; i < parameterList.length; i++) { let param = parameterList[i]; @@ -8599,6 +8598,7 @@ module ts { } } } + return -1; } function isInLegalTypePredicatePosition(node: Node): boolean { @@ -8639,7 +8639,7 @@ module ts { if (typePredicate.parameterIndex >= 0) { if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) { error(typePredicateNode.parameterName, - Diagnostics.Type_predicate_cannot_reference_a_rest_parameter); + Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); } else { checkTypeAssignableTo(typePredicate.type, @@ -8656,24 +8656,24 @@ module ts { if (param.name.kind === SyntaxKind.ObjectBindingPattern || param.name.kind === SyntaxKind.ArrayBindingPattern) { - (function checkBindingPattern(elements: NodeArray) { - for (let element of elements) { + (function checkBindingPattern(pattern: BindingPattern) { + for (let element of pattern.elements) { if (element.name.kind === SyntaxKind.Identifier && (element.name).text === typePredicate.parameterName) { error(typePredicateNode.parameterName, - Diagnostics.Type_predicate_cannot_reference_element_0_in_a_binding_pattern, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, typePredicate.parameterName); hasReportedError = true; break; } - else if(element.name.kind === SyntaxKind.ArrayBindingPattern || + else if (element.name.kind === SyntaxKind.ArrayBindingPattern || element.name.kind === SyntaxKind.ObjectBindingPattern) { - checkBindingPattern((element.name).elements); + checkBindingPattern(element.name); } } - })((param.name).elements); + })(param.name); } } if (!hasReportedError) { @@ -8685,7 +8685,7 @@ module ts { } else { error(typePredicateNode, - Diagnostics.Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods); + Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); } } else { @@ -11327,7 +11327,7 @@ module ts { function checkTypePredicate(node: TypePredicateNode) { if(!isInLegalTypePredicatePosition(node)) { - error(node, Diagnostics.Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods); + error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 1a79f4b2f44..51a955ea59c 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -183,9 +183,9 @@ module ts { Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." }, Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." }, Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." }, - Type_predicate_are_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicate are only allowed in return type position for functions and methods." }, - Type_predicate_cannot_reference_a_rest_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a rest parameter." }, - Type_predicate_cannot_reference_element_0_in_a_binding_pattern: { code: 1230, category: DiagnosticCategory.Error, key: "Type predicate cannot reference element '{0}' in a binding pattern." }, + A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "A type predicate is only allowed in return type position for functions and methods." }, + A_type_predicate_cannot_reference_a_rest_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "A type predicate cannot reference a rest parameter." }, + A_type_predicate_cannot_reference_element_0_in_a_binding_pattern: { code: 1230, category: DiagnosticCategory.Error, key: "A type predicate cannot reference element '{0}' in a binding pattern." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6ffc62a66ee..567ccd86303 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -719,15 +719,15 @@ "category": "Error", "code": 1227 }, - "Type predicate are only allowed in return type position for functions and methods.": { + "A type predicate is only allowed in return type position for functions and methods.": { "category": "Error", "code": 1228 }, - "Type predicate cannot reference a rest parameter.": { + "A type predicate cannot reference a rest parameter.": { "category": "Error", "code": 1229 }, - "Type predicate cannot reference element '{0}' in a binding pattern.": { + "A type predicate cannot reference element '{0}' in a binding pattern.": { "category": "Error", "code": 1230 }, diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 7fa26b41217..1542bbe0fee 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -20,20 +20,20 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,9): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,16): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(94,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,9): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,16): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(94,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(101,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: Type predicate are only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,16): error TS2408: Setters cannot return a value. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,18): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,22): error TS1228: Type predicate are only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,20): error TS1229: Type predicate cannot reference a rest parameter. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(125,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39): error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,18): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,22): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,20): error TS1229: A type predicate cannot reference a rest parameter. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(125,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. ==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (30 errors) ==== @@ -168,13 +168,13 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39 // Type predicates in non-return type positions var b1: b is A; ~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. function b2(a: b is A) {}; ~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. function b3(): A | b is A { ~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; }; @@ -182,19 +182,19 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39 class D { constructor(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; } set m2(p1: A): p1 is C { ~~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2408: Setters cannot return a value. @@ -204,37 +204,37 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,39 interface I1 { new (p1: A): p1 is C; ~~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. } interface I2 { [index: number]: p1 is C; ~~~~~~~ -!!! error TS1228: Type predicate are only allowed in return type position for functions and methods. +!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. } // Reference to rest parameter function b4(...a): a is A { ~ -!!! error TS1229: Type predicate cannot reference a rest parameter. +!!! error TS1229: A type predicate cannot reference a rest parameter. return true; } // Reference to binding pattern function b5({a, b, p1}, p2, p3): p1 is A { ~~ -!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +!!! error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. return true; } function b6([a, b, p1], p2, p3): p1 is A { ~~ -!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +!!! error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. return true; } function b7({a, b, c: {p1}}, p2, p3): p1 is A { ~~ -!!! error TS1230: Type predicate cannot reference element 'p1' in a binding pattern. +!!! error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. return true; } \ No newline at end of file From 364cd1146ba2e4e0998fc419c0a51616b1c592d8 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 8 Jun 2015 18:31:56 -0700 Subject: [PATCH 33/40] move temp declarations out of object literal --- src/compiler/emitter.ts | 2 +- tests/baselines/reference/systemModule8.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index ddccfad3108..4c761c76411 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5389,10 +5389,10 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitSetters(exportStarFunction); writeLine(); emitExecute(node, startIndex); - emitTempDeclarations(/*newLine*/ true) decreaseIndent(); writeLine(); write("}"); // return + emitTempDeclarations(/*newLine*/ true) } function emitSetters(exportStarFunction: string) { diff --git a/tests/baselines/reference/systemModule8.js b/tests/baselines/reference/systemModule8.js index 6196005dc62..be4f8c05374 100644 --- a/tests/baselines/reference/systemModule8.js +++ b/tests/baselines/reference/systemModule8.js @@ -65,6 +65,6 @@ System.register([], function(exports_1) { exports_1("x", x = _b[_i][0]); } } - var _a; } + var _a; }); From 7b67ac243cb0a4524fdeaaf92697517176e48189 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 9 Jun 2015 06:48:20 -0700 Subject: [PATCH 34/40] Addressing CR feedback --- src/compiler/checker.ts | 8 ++++++-- src/compiler/emitter.ts | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1076fac90b7..7132a4b711a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11790,10 +11790,14 @@ module ts { let symbol = getReferencedValueSymbol(node); if (symbol) { if (symbol.flags & SymbolFlags.ExportValue) { + // If we reference an exported entity within the same module declaration, then whether + // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the + // kinds that we do NOT prefix. let exportSymbol = getMergedSymbol(symbol.exportSymbol); - if (!(exportSymbol.flags & SymbolFlags.ExportHasLocal)) { - symbol = exportSymbol; + if (exportSymbol.flags & SymbolFlags.ExportHasLocal) { + return undefined; } + symbol = exportSymbol; } let parentSymbol = getParentOfSymbol(symbol); if (parentSymbol) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2ad3f3634ee..50421c61f46 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2841,6 +2841,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { + // We create a synthetic copy of the identifier in order to avoid the rewriting that might + // otherwise occur when the identifier is emitted. let syntheticName = createSynthesizedNode(propName.kind); syntheticName.text = propName.text; if (syntheticName.kind !== SyntaxKind.Identifier) { From 75ed565f81de746cdbec8ff0a229391e94bfd52f Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 9 Jun 2015 11:12:00 -0700 Subject: [PATCH 35/40] Don't consume 'is' keyword if there is a preceding line terminator --- src/compiler/parser.ts | 2 +- tests/baselines/reference/typePredicateASI.js | 7 +++++++ tests/baselines/reference/typePredicateASI.symbols | 14 ++++++++++++++ tests/baselines/reference/typePredicateASI.types | 14 ++++++++++++++ .../expressions/typeGuards/typePredicateASI.ts | 4 ++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/typePredicateASI.js create mode 100644 tests/baselines/reference/typePredicateASI.symbols create mode 100644 tests/baselines/reference/typePredicateASI.types create mode 100644 tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 92f3e68f2ac..394bb0f401d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1903,7 +1903,7 @@ module ts { function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode { let typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); - if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword) { + if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { nextToken(); let node = createNode(SyntaxKind.TypePredicate, typeName.pos); node.parameterName = typeName; diff --git a/tests/baselines/reference/typePredicateASI.js b/tests/baselines/reference/typePredicateASI.js new file mode 100644 index 00000000000..887ce121c0b --- /dev/null +++ b/tests/baselines/reference/typePredicateASI.js @@ -0,0 +1,7 @@ +//// [typePredicateASI.ts] +interface I { + foo(callback: (a: any, b: any) => void): I + is(): boolean; +} + +//// [typePredicateASI.js] diff --git a/tests/baselines/reference/typePredicateASI.symbols b/tests/baselines/reference/typePredicateASI.symbols new file mode 100644 index 00000000000..c451c4caf06 --- /dev/null +++ b/tests/baselines/reference/typePredicateASI.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts === +interface I { +>I : Symbol(I, Decl(typePredicateASI.ts, 0, 0)) + + foo(callback: (a: any, b: any) => void): I +>foo : Symbol(foo, Decl(typePredicateASI.ts, 0, 13)) +>callback : Symbol(callback, Decl(typePredicateASI.ts, 1, 8)) +>a : Symbol(a, Decl(typePredicateASI.ts, 1, 19)) +>b : Symbol(b, Decl(typePredicateASI.ts, 1, 26)) +>I : Symbol(I, Decl(typePredicateASI.ts, 0, 0)) + + is(): boolean; +>is : Symbol(is, Decl(typePredicateASI.ts, 1, 46)) +} diff --git a/tests/baselines/reference/typePredicateASI.types b/tests/baselines/reference/typePredicateASI.types new file mode 100644 index 00000000000..2be5e4c755b --- /dev/null +++ b/tests/baselines/reference/typePredicateASI.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts === +interface I { +>I : I + + foo(callback: (a: any, b: any) => void): I +>foo : (callback: (a: any, b: any) => void) => I +>callback : (a: any, b: any) => void +>a : any +>b : any +>I : I + + is(): boolean; +>is : () => boolean +} diff --git a/tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts b/tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts new file mode 100644 index 00000000000..60174710690 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typePredicateASI.ts @@ -0,0 +1,4 @@ +interface I { + foo(callback: (a: any, b: any) => void): I + is(): boolean; +} \ No newline at end of file From 28abe4d640938615e4e6490d815b65817cadf1d9 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 9 Jun 2015 13:41:50 -0700 Subject: [PATCH 36/40] Remove bad character in checker --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c40e43c8717..3cb368177f9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1358,7 +1358,7 @@ module ts { return result; } - function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { let writer = getSingleLineStringWriter(); getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); let result = writer.string(); From 2a29839805d28339faeb43b6c298afbfea5e40e1 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 9 Jun 2015 13:52:13 -0700 Subject: [PATCH 37/40] Retype the text instead of removing the bad character --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cb368177f9..57f3d737927 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1358,7 +1358,7 @@ module ts { return result; } - function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { let writer = getSingleLineStringWriter(); getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); let result = writer.string(); From 13ed900e66f5fa11260cbf41459f95ba0b2529ac Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 9 Jun 2015 14:58:56 -0700 Subject: [PATCH 38/40] Encode compiler files as UTF8. --- src/compiler/checker.ts | 13 +++++++------ src/compiler/emitter.ts | 18 ++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 57f3d737927..c8150d644a2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3603,7 +3603,8 @@ module ts { function getTypeFromTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments): Type { let links = getNodeLinks(node); if (!links.resolvedType) { - // We only support expressions that are simple qualified names. For other expressions this produces undefined. let typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName : + // We only support expressions that are simple qualified names. For other expressions this produces undefined. + let typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (node).typeName : isSupportedExpressionWithTypeArguments(node) ? (node).expression : undefined; let symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol; @@ -5255,14 +5256,14 @@ module ts { if (source.typePredicate && target.typePredicate) { if (target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) { // Return types from type predicates are treated as booleans. In order to infer types - // from type predicates we would need to infer from the type of type predicates. Since - // we can't infer any type information from the return types — we can just add a return - // statement after the below infer type statement. + // from type predicates we would need to infer using the type within the type predicate + // (i.e. 'Foo' from 'x is Foo'). inferFromTypes(source.typePredicate.type, target.typePredicate.type); } - return; } - inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + else { + inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + } } function inferFromIndexTypes(source: Type, target: Type, sourceKind: IndexKind, targetKind: IndexKind) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2f29ce0b405..df40d10ddf1 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1903,23 +1903,21 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { function emitNewExpression(node: NewExpression) { write("new "); - // Spread operator logic can be supported in new expressions in ES5 using a combination + // Spread operator logic is supported in new expressions in ES5 using a combination // of Function.prototype.bind() and Function.prototype.apply(). // // Example: // - // var arguments = [1, 2, 3, 4, 5]; - // new Array(...arguments); + // var args = [1, 2, 3, 4, 5]; + // new Array(...args); // - // Could be transpiled into ES5: + // is compiled into the following ES5: // - // var arguments = [1, 2, 3, 4, 5]; - // new (Array.bind.apply(Array, [void 0].concat(arguments))); + // var args = [1, 2, 3, 4, 5]; + // new (Array.bind.apply(Array, [void 0].concat(args))); // - // `[void 0]` is the first argument which represents `thisArg` to the bind method above. - // And `thisArg` will be set to the return value of the constructor when instantiated - // with the new operator — regardless of any value we set `thisArg` to. Thus, we set it - // to an undefined, `void 0`. + // The 'thisArg' to 'bind' is ignored when invoking the result of 'bind' with 'new', + // Thus, we set it to undefined ('void 0'). if (languageVersion === ScriptTarget.ES5 && node.arguments && hasSpreadElement(node.arguments)) { From 245dbab772d708a3b7db8c638f52a3675ff3dc55 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 9 Jun 2015 15:49:21 -0700 Subject: [PATCH 39/40] Removed 'debugger' statements from tests. --- tests/cases/fourslash/commentsMultiModuleMultiFile.ts | 1 - tests/cases/fourslash/completionListWithAmbientDeclaration.ts | 1 - tests/cases/fourslash/definitionNameOnEnumMember.ts | 1 - tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts | 1 - tests/cases/fourslash/formattingSkippedTokens.ts | 1 - tests/cases/fourslash/getEmitOutputWithDeclarationFile3.ts | 1 - .../getEmitOutputWithSemanticErrorsForMultipleFiles.ts | 1 - tests/cases/fourslash/getOccurrencesTryCatchFinally.ts | 1 - tests/cases/fourslash/navigateItemsLet.ts | 2 +- tests/cases/fourslash/navigationItemsExactMatch2.ts | 2 +- tests/cases/fourslash/navigationItemsOverloads2.ts | 2 +- tests/cases/fourslash/navigationItemsSubStringMatch.ts | 1 - tests/cases/fourslash/navigationItemsSubStringMatch2.ts | 1 - tests/cases/fourslash/quickInfoDisplayPartsConst.ts | 1 - tests/cases/fourslash/quickInfoDisplayPartsVar.ts | 1 - 15 files changed, 3 insertions(+), 15 deletions(-) diff --git a/tests/cases/fourslash/commentsMultiModuleMultiFile.ts b/tests/cases/fourslash/commentsMultiModuleMultiFile.ts index 40d7b6d9bc4..9516ddc9abb 100644 --- a/tests/cases/fourslash/commentsMultiModuleMultiFile.ts +++ b/tests/cases/fourslash/commentsMultiModuleMultiFile.ts @@ -28,7 +28,6 @@ // this line triggers a semantic/syntactic error check, remove line when 788570 is fixed edit.insert(''); -debugger; goTo.marker('1'); verify.completionListContains("multiM", "namespace multiM", "this is multi declare namespace\nthi is multi namespace 2\nthis is multi namespace 3 comment"); diff --git a/tests/cases/fourslash/completionListWithAmbientDeclaration.ts b/tests/cases/fourslash/completionListWithAmbientDeclaration.ts index 9fb4ffef90e..5839608b099 100644 --- a/tests/cases/fourslash/completionListWithAmbientDeclaration.ts +++ b/tests/cases/fourslash/completionListWithAmbientDeclaration.ts @@ -7,7 +7,6 @@ //// declare module 'https' { //// } //// /*2*/ -debugger; goTo.marker("1"); verify.not.completionListContains("http"); goTo.marker("2"); diff --git a/tests/cases/fourslash/definitionNameOnEnumMember.ts b/tests/cases/fourslash/definitionNameOnEnumMember.ts index 3844d4a46f3..d88e1ef688e 100644 --- a/tests/cases/fourslash/definitionNameOnEnumMember.ts +++ b/tests/cases/fourslash/definitionNameOnEnumMember.ts @@ -7,6 +7,5 @@ ////} ////var enumMember = e./*1*/thirdMember; -debugger; goTo.marker("1"); verify.verifyDefinitionsName("thirdMember", "e"); \ No newline at end of file diff --git a/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts b/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts index a929e67687f..1775075f68e 100644 --- a/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts +++ b/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts @@ -34,7 +34,6 @@ goTo.position(0); // : |--- delete "\n\n///..." // 1: // 2: -debugger; edit.deleteAtCaret(100); diff --git a/tests/cases/fourslash/formattingSkippedTokens.ts b/tests/cases/fourslash/formattingSkippedTokens.ts index 3b8ec47bf38..d3e76e97354 100644 --- a/tests/cases/fourslash/formattingSkippedTokens.ts +++ b/tests/cases/fourslash/formattingSkippedTokens.ts @@ -8,7 +8,6 @@ /////*4*/ : T) { } ////} /////*5*/var x = -debugger; format.document(); goTo.marker('1'); verify.currentLineContentIs('foo(): Bar { }'); diff --git a/tests/cases/fourslash/getEmitOutputWithDeclarationFile3.ts b/tests/cases/fourslash/getEmitOutputWithDeclarationFile3.ts index 60f7b433149..dfcf49c0e1f 100644 --- a/tests/cases/fourslash/getEmitOutputWithDeclarationFile3.ts +++ b/tests/cases/fourslash/getEmitOutputWithDeclarationFile3.ts @@ -18,5 +18,4 @@ // @Filename: inputFile5.js //// var x2 = 1000; -debugger; verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts index d24bcfbf504..0c6f4786c25 100644 --- a/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts +++ b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts @@ -12,5 +12,4 @@ // @Filename: inputFile2.ts //// // File not emitted, and contains semantic errors //// var semanticError: boolean = "string"; -debugger; verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts b/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts index db0f792880e..4b9a47cfe5c 100644 --- a/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts +++ b/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts @@ -16,7 +16,6 @@ ////[|fina/*3*/lly|] { ////} -debugger; for (var i = 1; i <= test.markers().length; i++) { goTo.marker("" + i); verify.occurrencesAtPositionCount(3); diff --git a/tests/cases/fourslash/navigateItemsLet.ts b/tests/cases/fourslash/navigateItemsLet.ts index 8a82d042738..8d6886ceb69 100644 --- a/tests/cases/fourslash/navigateItemsLet.ts +++ b/tests/cases/fourslash/navigateItemsLet.ts @@ -4,7 +4,7 @@ ////function foo() { //// {| "itemName": "d", "kind": "let", "parentName": "foo" |}let d = 10; ////} -debugger; + test.markers().forEach(marker => { verify.navigationItemsListContains( marker.data.itemName, diff --git a/tests/cases/fourslash/navigationItemsExactMatch2.ts b/tests/cases/fourslash/navigationItemsExactMatch2.ts index e96d4f65ed4..1bf4552a49b 100644 --- a/tests/cases/fourslash/navigationItemsExactMatch2.ts +++ b/tests/cases/fourslash/navigationItemsExactMatch2.ts @@ -17,7 +17,7 @@ ////function distance2(distanceParam1): void { //// var distanceLocal1; ////} -debugger; + goTo.marker("file1"); verify.navigationItemsListCount(2, "point", "exact"); verify.navigationItemsListCount(5, "distance", "prefix"); diff --git a/tests/cases/fourslash/navigationItemsOverloads2.ts b/tests/cases/fourslash/navigationItemsOverloads2.ts index 98908c84e98..2c33ef65f0d 100644 --- a/tests/cases/fourslash/navigationItemsOverloads2.ts +++ b/tests/cases/fourslash/navigationItemsOverloads2.ts @@ -8,5 +8,5 @@ ////interface I { //// interfaceMethodSignature(b: boolean): boolean; ////} -debugger; + verify.navigationItemsListCount(2, "interfaceMethodSignature", "exact"); diff --git a/tests/cases/fourslash/navigationItemsSubStringMatch.ts b/tests/cases/fourslash/navigationItemsSubStringMatch.ts index 4be74953142..071a1ae212f 100644 --- a/tests/cases/fourslash/navigationItemsSubStringMatch.ts +++ b/tests/cases/fourslash/navigationItemsSubStringMatch.ts @@ -17,7 +17,6 @@ ////// Local variables ////{| "itemName": "MymyPointThatIJustInitiated", "kind": "var", "parentName": "", "matchKind": "substring"|}var MymyPointThatIJustInitiated = new Shapes.Point(); -debugger; test.markers().forEach((marker) => { if (marker.data) { var name = marker.data.itemName; diff --git a/tests/cases/fourslash/navigationItemsSubStringMatch2.ts b/tests/cases/fourslash/navigationItemsSubStringMatch2.ts index 7ea901c9de3..5c7e3e5d202 100644 --- a/tests/cases/fourslash/navigationItemsSubStringMatch2.ts +++ b/tests/cases/fourslash/navigationItemsSubStringMatch2.ts @@ -17,7 +17,6 @@ //// INITIATED123; //// public horizon(): void; ////} -debugger; var notFoundSearchValue = "mPointThatIJustInitiated wrongKeyWord"; goTo.marker("file1"); diff --git a/tests/cases/fourslash/quickInfoDisplayPartsConst.ts b/tests/cases/fourslash/quickInfoDisplayPartsConst.ts index b3d601368b9..1e600e82775 100644 --- a/tests/cases/fourslash/quickInfoDisplayPartsConst.ts +++ b/tests/cases/fourslash/quickInfoDisplayPartsConst.ts @@ -22,7 +22,6 @@ /////*15*/h(10); /////*16*/h("hello"); -debugger; var marker = 0; function verifyConst(name: string, typeDisplay: ts.SymbolDisplayPart[], optionalNameDisplay?: ts.SymbolDisplayPart[], optionalKindModifiers?: string) { marker++; diff --git a/tests/cases/fourslash/quickInfoDisplayPartsVar.ts b/tests/cases/fourslash/quickInfoDisplayPartsVar.ts index a1f150d2457..d7666bace34 100644 --- a/tests/cases/fourslash/quickInfoDisplayPartsVar.ts +++ b/tests/cases/fourslash/quickInfoDisplayPartsVar.ts @@ -15,7 +15,6 @@ ////var /*11*/i = /*12*/h; /////*13*/h(10); /////*14*/h("hello"); -debugger; var marker = 0; function verifyVar(name: string, typeDisplay: ts.SymbolDisplayPart[], optionalNameDisplay?: ts.SymbolDisplayPart[], optionalKindModifiers?: string) { marker++; From caf0939d508b80fadbb02fd4f44e1b91376e2bc6 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 9 Jun 2015 16:47:43 -0700 Subject: [PATCH 40/40] Removed more 'debugger' statements from tests. --- tests/cases/unittests/services/colorization.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cases/unittests/services/colorization.ts b/tests/cases/unittests/services/colorization.ts index 4351f0ccb1d..da1fa91036c 100644 --- a/tests/cases/unittests/services/colorization.ts +++ b/tests/cases/unittests/services/colorization.ts @@ -66,7 +66,6 @@ describe('Colorization', function () { describe("test getClassifications", function () { it("Returns correct token classes", function () { - debugger; testLexicalClassification("var x: string = \"foo\"; //Hello", ts.EndOfLineState.None, keyword("var"), @@ -138,7 +137,6 @@ describe('Colorization', function () { }); it("correctly classifies the continuing line of a multi-line string ending in one backslash", function () { - debugger; testLexicalClassification("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"),