From 9515947092941127079a06a8d3d6bac245898835 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 2 Jun 2015 12:49:07 +0800 Subject: [PATCH 01/18] 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 fad7293412..a09a2736aa 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 8ccc9d890e..5a87f67ddd 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 fb246955f7..0053b07143 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 80c70a250f..ac4517a0b7 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 89ac837ab2..d7e65dff81 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 0fcf0e1f67..acf71db16c 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 02/18] 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 cd2df23ffb..9b2675535f 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 03/18] 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 0000000000..d6b64c09d4 --- /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 0000000000..f9180d56b0 --- /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 0000000000..2b3d1c40c8 --- /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 0000000000..8b5ed551df --- /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 0000000000..cc65fc00cb --- /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 0000000000..6704225a0d --- /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 0000000000..0ad8fab2fd --- /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 0000000000..77162e55a4 --- /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 0000000000..65d99319d1 --- /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 0000000000..a7bd0f4c16 --- /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 0000000000..b14e5e2291 --- /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 0000000000..d5faee96e8 --- /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 0000000000..37249ef765 --- /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 0000000000..3a659d7116 --- /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 0000000000..93cfd90ceb --- /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 0000000000..28a512aca6 --- /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 0000000000..d0e108b573 --- /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 0000000000..9f5ca611ee --- /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 0000000000..a199aeb1e6 --- /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 04/18] 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 a09a2736aa..5a33748fb0 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 5a87f67ddd..aba138b9a1 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 0053b07143..a94839fba7 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 ac4517a0b7..0f84ec2038 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 0000000000..246f84ccc0 --- /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 0000000000..dcc7eca43c --- /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 0000000000..80ae65a7dd --- /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 05/18] 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 5a33748fb0..80477ea184 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 aba138b9a1..46c1cd37b3 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 a94839fba7..ebcba6386f 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 8b5ed551df..001fe8a14a 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 06/18] 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 80477ea184..c75ba19df2 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 19e725636e25c6a42c3d729f917b6052053d2f2f Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 19:23:07 +0800 Subject: [PATCH 07/18] 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 c75ba19df2..a6ff7bfc51 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 46c1cd37b3..a949c5c034 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 ebcba6386f..a3e4e8c6e5 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 0f84ec2038..818e626b5a 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 acf71db16c..afdfe651c6 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 001fe8a14a..47479b221a 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 cc65fc00cb..84dd534f9d 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 246f84ccc0..0000000000 --- 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 dcc7eca43c..0000000000 --- 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 80ae65a7dd..0000000000 --- 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 08/18] 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 a6ff7bfc51..1f5e9a5264 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 818e626b5a..9a1ec11668 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 09/18] 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 1f5e9a5264..66898ebcbc 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 76bc9be701fa71436a2f73419c0c6adb0585b0db Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 4 Jun 2015 22:20:46 +0800 Subject: [PATCH 10/18] 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 66898ebcbc..46405f1f0f 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 11/18] 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 46405f1f0f..178328ae19 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 12/18] 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 178328ae19..0ba81bfa12 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 a73bf31c86fb94b381069843d67e4fb85c9c107f Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Fri, 5 Jun 2015 13:47:40 +0800 Subject: [PATCH 13/18] 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 0ba81bfa12..02e20888c9 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 14/18] 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 02e20888c9..72bfc80ac4 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 a949c5c034..1457b52ba7 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 a3e4e8c6e5..3c323f1402 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 9a1ec11668..86c7ee98a0 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 afdfe651c6..cdcdd924b3 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 47479b221a..0d5065395a 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 84dd534f9d..0617cc1495 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 28a512aca6..baae822ec2 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 487dff564fe4ec87fc1d445475deeb86b98224d7 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sat, 6 Jun 2015 11:27:55 +0800 Subject: [PATCH 15/18] 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 72bfc80ac4..c7ccb98f8f 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 1457b52ba7..25d3730cc0 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 3c323f1402..4008a6af1b 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 d6b64c09d4..5c256160bb 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 f9180d56b0..5b5fe1ec85 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 2b3d1c40c8..06e9be615e 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 0d5065395a..bcef83601a 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 0617cc1495..2d3ccc561e 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 93cfd90ceb..316a148338 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 baae822ec2..df1d0b974c 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 b1a8a5fe664fbe96a0c0bbad3c4003aa13958407 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Sun, 7 Jun 2015 18:31:53 +0800 Subject: [PATCH 16/18] 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 c7ccb98f8f..720a2352b4 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 25d3730cc0..96480f17ac 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 4008a6af1b..64b9c93fd6 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 5c256160bb..f6b752c8c0 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 5b5fe1ec85..c315e72108 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 06e9be615e..cf673f965f 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 bcef83601a..337dcd317c 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 2d3ccc561e..354aae2f2a 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 316a148338..57d56ccc3b 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 df1d0b974c..e7012a172b 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 17/18] 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 720a2352b4..4514834a9f 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 96480f17ac..1a79f4b2f4 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 64b9c93fd6..6ffc62a66e 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 337dcd317c..7fa26b4121 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 354aae2f2a..179a3b80cf 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 e7012a172b..e157b2afe3 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 ebe755b1865d82de7094943f771105d540cc0047 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 9 Jun 2015 07:32:03 +0800 Subject: [PATCH 18/18] 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 4514834a9f..af1e9349ee 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 1a79f4b2f4..51a955ea59 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 6ffc62a66e..567ccd8630 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 7fa26b4121..1542bbe0fe 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