Fix narrowing, interfaces. Expose issue with generic instantiation

This commit is contained in:
Wesley Wigham
2015-12-07 18:16:05 -08:00
parent b9f310d4f2
commit be6e341d2a
5 changed files with 101 additions and 22 deletions

View File

@@ -1189,7 +1189,8 @@ namespace ts {
case SyntaxKind.ThisType:
seenThisKeyword = true;
return;
case SyntaxKind.TypePredicate:
return checkTypePredicate(node as TypePredicateNode);
case SyntaxKind.TypeParameter:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
case SyntaxKind.Parameter:
@@ -1275,6 +1276,16 @@ namespace ts {
}
}
function checkTypePredicate(node: TypePredicateNode) {
if (node.parameterName && node.parameterName.kind === SyntaxKind.Identifier) {
checkStrictModeIdentifier(node.parameterName as Identifier);
}
if (node.parameterName && node.parameterName.kind === SyntaxKind.ThisType) {
seenThisKeyword = true;
}
bind(node.type);
}
function bindSourceFileIfExternalModule() {
setExportContextFlag(file);
if (isExternalModule(file)) {

View File

@@ -2634,7 +2634,13 @@ namespace ts {
// During a normal type check we'll never get to here with a property assignment (the check of the containing
// object literal uses a different path). We exclude widening only so that language services and type verification
// tools see the actual type.
return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type;
if (declaration.kind === SyntaxKind.PropertyAssignment) {
return type;
}
if (type.flags & TypeFlags.PredicateType && (declaration.kind === SyntaxKind.PropertyDeclaration || declaration.kind === SyntaxKind.PropertySignature)) {
return type;
}
return getWidenedType(type);
}
// Rest parameters default to type any[], other parameters default to type any
@@ -4602,7 +4608,7 @@ namespace ts {
}
function getPredicateType(node: TypePredicateNode): Type {
if (!(node.parent.kind === SyntaxKind.PropertyDeclaration || node.parent.kind === SyntaxKind.GetAccessor)) {
if (!(node.parent.kind === SyntaxKind.PropertyDeclaration || node.parent.kind === SyntaxKind.PropertySignature || node.parent.kind === SyntaxKind.GetAccessor)) {
return booleanType;
}
else {
@@ -6008,6 +6014,9 @@ namespace ts {
function getWidenedType(type: Type): Type {
if (type.flags & TypeFlags.RequiresWidening) {
if (type.flags & TypeFlags.PredicateType) {
return booleanType;
}
if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
return anyType;
}
@@ -11078,8 +11087,9 @@ namespace ts {
}
switch (node.parent.kind) {
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.GetAccessor:
return node === (<SignatureDeclaration>node.parent).type;
return node === (node.parent as (PropertyDeclaration | GetAccessorDeclaration | PropertySignature)).type;
}
return false;
}
@@ -11104,12 +11114,8 @@ namespace ts {
if (node.type.kind === SyntaxKind.TypePredicate) {
const typePredicate = getSignatureFromDeclaration(node).typePredicate;
const typePredicateNode = <TypePredicateNode>node.type;
checkSourceElement(typePredicateNode);
if (isIdentifierTypePredicate(typePredicate)) {
if (!isInLegalTypePredicatePosition(typePredicateNode)) {
error(typePredicateNode,
Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
return;
}
if (typePredicate.parameterIndex >= 0) {
if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) {
error(typePredicateNode.parameterName,
@@ -11157,15 +11163,6 @@ namespace ts {
}
}
}
else {
if (!isInLegalThisTypePredicatePosition(typePredicateNode)) {
error(typePredicateNode,
Diagnostics.A_this_based_type_predicate_is_only_allowed_in_class_or_interface_members_get_accessors_or_return_type_positions_for_functions_and_methods);
return;
}
// Reuse this type diagnostics on the this type node to determine if a this type predicate is valid
getTypeFromThisTypeNode(typePredicateNode.parameterName as ThisTypeNode);
}
}
else {
checkSourceElement(node.type);
@@ -14295,8 +14292,13 @@ namespace ts {
if (node.parameterName.kind === SyntaxKind.Identifier && !isInLegalTypePredicatePosition(node)) {
error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
}
else if (node.parameterName.kind === SyntaxKind.ThisType && (!isInLegalThisTypePredicatePosition(node) || getTypeFromThisTypeNode(node.parameterName as ThisTypeNode) === unknownType)) {
error(node, Diagnostics.A_this_based_type_predicate_is_only_allowed_in_class_or_interface_members_get_accessors_or_return_type_positions_for_functions_and_methods);
else if (node.parameterName.kind === SyntaxKind.ThisType) {
if (!isInLegalThisTypePredicatePosition(node)) {
error(node, Diagnostics.A_this_based_type_predicate_is_only_allowed_in_class_or_interface_members_get_accessors_or_return_type_positions_for_functions_and_methods);
}
else {
getTypeFromThisTypeNode(node.parameterName as ThisTypeNode);
}
}
}

View File

@@ -2120,7 +2120,7 @@ namespace ts {
UnionOrIntersection = Union | Intersection,
StructuredType = ObjectType | Union | Intersection,
/* @internal */
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral | PredicateType,
/* @internal */
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
}

View File

@@ -133,3 +133,9 @@ if (mimic.isFollower()) {
mimic.follow();
mimic.isFollower = a.isFollower;
}
interface MimicGuardInterface {
isLeader(): this is LeadGuard;
isFollower(): this is FollowerGuard;
}

View File

@@ -40,4 +40,64 @@ namespace Test {
else if (file.isNetworked) {
file.host;
}
}
interface GenericLeadGuard<T> extends GenericGuard<T> {
lead(): void;
}
interface GenericFollowerGuard<T> extends GenericGuard<T> {
follow(): void;
}
interface GenericGuard<T> {
target: T;
isLeader: this is (GenericLeadGuard<T>);
isFollower: this is GenericFollowerGuard<T>;
}
let guard: GenericGuard<File>;
if (guard.isLeader) {
guard.lead();
}
else if (guard.isFollower) {
guard.follow();
}
interface SpecificGuard {
isMoreSpecific: this is MoreSpecificGuard;
}
interface MoreSpecificGuard extends SpecificGuard {
do(): void;
}
let general: SpecificGuard;
if (general.isMoreSpecific) {
general.do();
}
class doThing<T> {
constructor(private x: T) {}
isThing(x: any): x is doThing<T> {
return true;
}
}
let z: doThing<{}> = new doThing({x: 10});
let z1 = new doThing({x: 10});
if (z1.isThing(z)) {
z;
}
}
function f(g: (x: number) => void) {
}
f(function(x) {
})