Skip to content

Commit

Permalink
Merge pull request #6744 from Microsoft/removePredicateTypiness
Browse files Browse the repository at this point in the history
Remove notion of predicates as types, move predicates back to signatures
  • Loading branch information
DanielRosenwasser committed Feb 12, 2016
2 parents e7899cf + 74b1e3f commit 5a76a1d
Show file tree
Hide file tree
Showing 58 changed files with 1,114 additions and 926 deletions.
257 changes: 122 additions & 135 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,10 @@
"category": "Error",
"code": 1227
},
"A type predicate is only allowed in return type position for functions and methods.": {
"category": "Error",
"code": 1228
},
"A type predicate cannot reference a rest parameter.": {
"category": "Error",
"code": 1229
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1940,7 +1940,7 @@ namespace ts {
return finishNode(node);
}

function parseTypePredicate(lhs: Identifier | ThisTypeNode): TypePredicateNode {
function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {
nextToken();
const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode;
node.parameterName = lhs;
Expand Down Expand Up @@ -2399,7 +2399,7 @@ namespace ts {
case SyntaxKind.ThisKeyword: {
const thisKeyword = parseThisTypeNode();
if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
return parseTypePredicate(thisKeyword);
return parseThisTypePredicate(thisKeyword);
}
else {
return thisKeyword;
Expand Down
21 changes: 10 additions & 11 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1777,7 +1777,8 @@ namespace ts {
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void;
buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void;
buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
Expand Down Expand Up @@ -1842,22 +1843,24 @@ namespace ts {
Identifier
}

export interface TypePredicate {
export interface TypePredicateBase {
kind: TypePredicateKind;
type: Type;
}

// @kind (TypePredicateKind.This)
export interface ThisTypePredicate extends TypePredicate {
export interface ThisTypePredicate extends TypePredicateBase {
_thisTypePredicateBrand: any;
}

// @kind (TypePredicateKind.Identifier)
export interface IdentifierTypePredicate extends TypePredicate {
export interface IdentifierTypePredicate extends TypePredicateBase {
parameterName: string;
parameterIndex: number;
}

export type TypePredicate = IdentifierTypePredicate | ThisTypePredicate;

/* @internal */
export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration;

Expand Down Expand Up @@ -2125,7 +2128,6 @@ namespace ts {
ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6
ThisType = 0x02000000, // This type
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
PredicateType = 0x08000000, // Predicate types are also Boolean types, but should not be considered Intrinsics - there's no way to capture this with flags

/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
Expand All @@ -2137,7 +2139,7 @@ namespace ts {
UnionOrIntersection = Union | Intersection,
StructuredType = ObjectType | Union | Intersection,
/* @internal */
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral | PredicateType,
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
/* @internal */
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
}
Expand All @@ -2158,11 +2160,6 @@ namespace ts {
intrinsicName: string; // Name of intrinsic type
}

// Predicate types (TypeFlags.Predicate)
export interface PredicateType extends Type {
predicate: ThisTypePredicate | IdentifierTypePredicate;
}

// String literal types (TypeFlags.StringLiteral)
export interface StringLiteralType extends Type {
text: string; // Text of string literal
Expand Down Expand Up @@ -2297,6 +2294,8 @@ namespace ts {
erasedSignatureCache?: Signature; // Erased version of signature (deferred)
/* @internal */
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
/* @internal */
typePredicate?: TypePredicate;
}

export const enum IndexKind {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,10 @@ namespace ts {
return predicate && predicate.kind === TypePredicateKind.Identifier;
}

export function isThisTypePredicate(predicate: TypePredicate): predicate is ThisTypePredicate {
return predicate && predicate.kind === TypePredicateKind.This;
}

export function getContainingFunction(node: Node): FunctionLikeDeclaration {
while (true) {
node = node.parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var obj: Object;
>Object : Object

if (ArrayBuffer.isView(obj)) {
>ArrayBuffer.isView(obj) : arg is ArrayBufferView
>ArrayBuffer.isView(obj) : boolean
>ArrayBuffer.isView : (arg: any) => arg is ArrayBufferView
>ArrayBuffer : ArrayBufferConstructor
>isView : (arg: any) => arg is ArrayBufferView
Expand Down
16 changes: 16 additions & 0 deletions tests/baselines/reference/declarationEmitIdentifierPredicates01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [declarationEmitIdentifierPredicates01.ts]

export function f(x: any): x is number {
return typeof x === "number";
}

//// [declarationEmitIdentifierPredicates01.js]
"use strict";
function f(x) {
return typeof x === "number";
}
exports.f = f;


//// [declarationEmitIdentifierPredicates01.d.ts]
export declare function f(x: any): x is number;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
=== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitIdentifierPredicates01.ts ===

export function f(x: any): x is number {
>f : Symbol(f, Decl(declarationEmitIdentifierPredicates01.ts, 0, 0))
>x : Symbol(x, Decl(declarationEmitIdentifierPredicates01.ts, 1, 18))
>x : Symbol(x, Decl(declarationEmitIdentifierPredicates01.ts, 1, 18))

return typeof x === "number";
>x : Symbol(x, Decl(declarationEmitIdentifierPredicates01.ts, 1, 18))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
=== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitIdentifierPredicates01.ts ===

export function f(x: any): x is number {
>f : (x: any) => x is number
>x : any
>x : any

return typeof x === "number";
>typeof x === "number" : boolean
>typeof x : string
>x : any
>"number" : string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
tests/cases/conformance/declarationEmit/typePredicates/declarationEmitIdentifierPredicatesWithPrivateName01.ts(6,33): error TS4060: Return type of exported function has or is using private name 'I'.


==== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitIdentifierPredicatesWithPrivateName01.ts (1 errors) ====

interface I {
a: number;
}

export function f(x: any): x is I {
~
!!! error TS4060: Return type of exported function has or is using private name 'I'.
return typeof x.a === "number";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [declarationEmitIdentifierPredicatesWithPrivateName01.ts]

interface I {
a: number;
}

export function f(x: any): x is I {
return typeof x.a === "number";
}

//// [declarationEmitIdentifierPredicatesWithPrivateName01.js]
"use strict";
function f(x) {
return typeof x.a === "number";
}
exports.f = f;
43 changes: 43 additions & 0 deletions tests/baselines/reference/declarationEmitThisPredicates01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//// [declarationEmitThisPredicates01.ts]

export class C {
m(): this is D {
return this instanceof D;
}
}

export class D extends C {
}

//// [declarationEmitThisPredicates01.js]
"use strict";
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; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var C = (function () {
function C() {
}
C.prototype.m = function () {
return this instanceof D;
};
return C;
}());
exports.C = C;
var D = (function (_super) {
__extends(D, _super);
function D() {
_super.apply(this, arguments);
}
return D;
}(C));
exports.D = D;


//// [declarationEmitThisPredicates01.d.ts]
export declare class C {
m(): this is D;
}
export declare class D extends C {
}
19 changes: 19 additions & 0 deletions tests/baselines/reference/declarationEmitThisPredicates01.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicates01.ts ===

export class C {
>C : Symbol(C, Decl(declarationEmitThisPredicates01.ts, 0, 0))

m(): this is D {
>m : Symbol(m, Decl(declarationEmitThisPredicates01.ts, 1, 16))
>D : Symbol(D, Decl(declarationEmitThisPredicates01.ts, 5, 1))

return this instanceof D;
>this : Symbol(C, Decl(declarationEmitThisPredicates01.ts, 0, 0))
>D : Symbol(D, Decl(declarationEmitThisPredicates01.ts, 5, 1))
}
}

export class D extends C {
>D : Symbol(D, Decl(declarationEmitThisPredicates01.ts, 5, 1))
>C : Symbol(C, Decl(declarationEmitThisPredicates01.ts, 0, 0))
}
20 changes: 20 additions & 0 deletions tests/baselines/reference/declarationEmitThisPredicates01.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicates01.ts ===

export class C {
>C : C

m(): this is D {
>m : () => this is D
>D : D

return this instanceof D;
>this instanceof D : boolean
>this : this
>D : typeof D
}
}

export class D extends C {
>D : D
>C : C
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicates02.ts(9,10): error TS2526: A 'this' type is available only in a non-static member of a class or interface.


==== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicates02.ts (1 errors) ====

export interface Foo {
a: string;
b: number;
c: boolean;
}

export const obj = {
m(): this is Foo {
~~~~
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
let dis = this as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}
34 changes: 34 additions & 0 deletions tests/baselines/reference/declarationEmitThisPredicates02.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [declarationEmitThisPredicates02.ts]

export interface Foo {
a: string;
b: number;
c: boolean;
}

export const obj = {
m(): this is Foo {
let dis = this as Foo;
return dis.a != null && dis.b != null && dis.c != null;
}
}

//// [declarationEmitThisPredicates02.js]
"use strict";
exports.obj = {
m: function () {
var dis = this;
return dis.a != null && dis.b != null && dis.c != null;
}
};


//// [declarationEmitThisPredicates02.d.ts]
export interface Foo {
a: string;
b: number;
c: boolean;
}
export declare const obj: {
m(): this is Foo;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicatesWithPrivateName01.ts(3,18): error TS4055: Return type of public method from exported class has or is using private name 'D'.


==== tests/cases/conformance/declarationEmit/typePredicates/declarationEmitThisPredicatesWithPrivateName01.ts (1 errors) ====

export class C {
m(): this is D {
~
!!! error TS4055: Return type of public method from exported class has or is using private name 'D'.
return this instanceof D;
}
}

class D extends C {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [declarationEmitThisPredicatesWithPrivateName01.ts]

export class C {
m(): this is D {
return this instanceof D;
}
}

class D extends C {
}

//// [declarationEmitThisPredicatesWithPrivateName01.js]
"use strict";
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; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var C = (function () {
function C() {
}
C.prototype.m = function () {
return this instanceof D;
};
return C;
}());
exports.C = C;
var D = (function (_super) {
__extends(D, _super);
function D() {
_super.apply(this, arguments);
}
return D;
}(C));
Loading

0 comments on commit 5a76a1d

Please sign in to comment.