Addresses PR feedback

This commit is contained in:
Tingan Ho
2015-06-03 15:29:06 +08:00
parent b7d1df68fb
commit b0542342c3
4 changed files with 66 additions and 58 deletions

View File

@@ -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((<UnionType>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((<UnionType>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((<UnionType>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((<UnionType>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);
}
}

View File

@@ -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." },

View File

@@ -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
},

View File

@@ -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;
};