From 311d20fa99a48eff5cff7f5d4ea311b95f7bd280 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 12:46:58 -0700 Subject: [PATCH 01/29] Fix bug #3737 (exported JSX classes props not validated) --- src/compiler/checker.ts | 18 +++---- .../tsxAttributeResolution9.errors.txt | 31 ++++++++++++ .../reference/tsxAttributeResolution9.js | 42 +++++++++++++++++ .../reference/tsxAttributeResolution9.symbols | 45 ++++++++++++++++++ .../reference/tsxAttributeResolution9.types | 47 +++++++++++++++++++ .../jsx/tsxAttributeResolution9.tsx | 27 +++++++++++ 6 files changed, 199 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/tsxAttributeResolution9.errors.txt create mode 100644 tests/baselines/reference/tsxAttributeResolution9.js create mode 100644 tests/baselines/reference/tsxAttributeResolution9.symbols create mode 100644 tests/baselines/reference/tsxAttributeResolution9.types create mode 100644 tests/cases/conformance/jsx/tsxAttributeResolution9.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3ef2c6ada2a..b910dc3306b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7095,13 +7095,18 @@ namespace ts { // Look up the value in the current scope if (node.tagName.kind === SyntaxKind.Identifier) { - valueSymbol = getResolvedSymbol(node.tagName); + let tag = node.tagName; + valueSymbol = resolveName(tag, tag.text, SymbolFlags.Value, Diagnostics.Cannot_find_name_0, tag.text); } else { valueSymbol = checkQualifiedName(node.tagName).symbol; } - if (valueSymbol !== unknownSymbol) { + if (valueSymbol && valueSymbol !== unknownSymbol) { + let symbolLinks = getSymbolLinks(valueSymbol); + if (symbolLinks) { + symbolLinks.referenced = true; + } links.jsxFlags |= JsxFlags.ClassElement; } @@ -7301,15 +7306,6 @@ namespace ts { let targetAttributesType = getJsxElementAttributesType(node); - if (getNodeLinks(node).jsxFlags & JsxFlags.ClassElement) { - if (node.tagName.kind === SyntaxKind.Identifier) { - checkIdentifier(node.tagName); - } - else { - checkQualifiedName(node.tagName); - } - } - let nameTable: Map = {}; // Process this array in right-to-left order so we know which // attributes (mostly from spreads) are being overwritten and diff --git a/tests/baselines/reference/tsxAttributeResolution9.errors.txt b/tests/baselines/reference/tsxAttributeResolution9.errors.txt new file mode 100644 index 00000000000..c25532eaa0a --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution9.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/jsx/file.tsx(9,14): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== + + declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } + } + + interface Props { + foo: string; + } + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + export class MyComponent { + render() { + } + + props: { foo: string; } + } + + ; // ok + ; // should be an error + ~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxAttributeResolution9.js b/tests/baselines/reference/tsxAttributeResolution9.js new file mode 100644 index 00000000000..bfc19a7ba4f --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution9.js @@ -0,0 +1,42 @@ +//// [tests/cases/conformance/jsx/tsxAttributeResolution9.tsx] //// + +//// [react.d.ts] + +declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } +} + +interface Props { + foo: string; +} + +//// [file.tsx] +export class MyComponent { + render() { + } + + props: { foo: string; } +} + +; // ok +; // should be an error + + +//// [file.jsx] +define(["require", "exports"], function (require, exports) { + var MyComponent = (function () { + function MyComponent() { + } + MyComponent.prototype.render = function () { + }; + return MyComponent; + })(); + exports.MyComponent = MyComponent; + ; // ok + ; // should be an error +}); diff --git a/tests/baselines/reference/tsxAttributeResolution9.symbols b/tests/baselines/reference/tsxAttributeResolution9.symbols new file mode 100644 index 00000000000..cbb30864c81 --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution9.symbols @@ -0,0 +1,45 @@ +=== tests/cases/conformance/jsx/tsxAttributeResolution9.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(tsxAttributeResolution9.tsx, 0, 0)) + + interface Element { } +>Element : Symbol(Element, Decl(tsxAttributeResolution9.tsx, 0, 20)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxAttributeResolution9.tsx, 1, 22)) + } + interface ElementAttributesProperty { +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(tsxAttributeResolution9.tsx, 3, 2)) + + props; +>props : Symbol(props, Decl(tsxAttributeResolution9.tsx, 4, 38)) + } +} + +interface Props { +>Props : Symbol(Props, Decl(tsxAttributeResolution9.tsx, 7, 1)) + + foo: string; +>foo : Symbol(foo, Decl(tsxAttributeResolution9.tsx, 9, 17)) +} + +export class MyComponent { +>MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) + + render() { +>render : Symbol(render, Decl(tsxAttributeResolution9.tsx, 13, 26)) + } + + props: { foo: string; } +>props : Symbol(props, Decl(tsxAttributeResolution9.tsx, 15, 3)) +>foo : Symbol(foo, Decl(tsxAttributeResolution9.tsx, 17, 10)) +} + +; // ok +>MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) +>foo : Symbol(unknown) + +; // should be an error +>MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) +>foo : Symbol(unknown) + diff --git a/tests/baselines/reference/tsxAttributeResolution9.types b/tests/baselines/reference/tsxAttributeResolution9.types new file mode 100644 index 00000000000..aab3806a5f0 --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution9.types @@ -0,0 +1,47 @@ +=== tests/cases/conformance/jsx/tsxAttributeResolution9.tsx === +declare module JSX { +>JSX : any + + interface Element { } +>Element : Element + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + } + interface ElementAttributesProperty { +>ElementAttributesProperty : ElementAttributesProperty + + props; +>props : any + } +} + +interface Props { +>Props : Props + + foo: string; +>foo : string +} + +export class MyComponent { +>MyComponent : MyComponent + + render() { +>render : () => void + } + + props: { foo: string; } +>props : { foo: string; } +>foo : string +} + +; // ok +> : any +>MyComponent : typeof MyComponent +>foo : any + +; // should be an error +> : any +>MyComponent : typeof MyComponent +>foo : any + diff --git a/tests/cases/conformance/jsx/tsxAttributeResolution9.tsx b/tests/cases/conformance/jsx/tsxAttributeResolution9.tsx new file mode 100644 index 00000000000..9768d65d000 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxAttributeResolution9.tsx @@ -0,0 +1,27 @@ +//@jsx: preserve +//@module: amd + +//@filename: react.d.ts +declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } +} + +interface Props { + foo: string; +} + +//@filename: file.tsx +export class MyComponent { + render() { + } + + props: { foo: string; } +} + +; // ok +; // should be an error From 48ae5ea6f87a0e22a57bea61db8f9d84669ba017 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 7 Jul 2015 13:25:39 -0700 Subject: [PATCH 02/29] Remove check if node is a block --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3ef2c6ada2a..7083feabb2c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11446,7 +11446,7 @@ namespace ts { function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node: Node) { if (node.modifiers) { - if (inBlockOrObjectLiteralExpression(node)) { + if (inObjectLiteralExpression(node)) { if (isAsyncFunctionLike(node)) { if (node.modifiers.length > 1) { return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); @@ -11459,9 +11459,9 @@ namespace ts { } } - function inBlockOrObjectLiteralExpression(node: Node) { + function inObjectLiteralExpression(node: Node) { while (node) { - if (node.kind === SyntaxKind.Block || node.kind === SyntaxKind.ObjectLiteralExpression) { + if (node.kind === SyntaxKind.ObjectLiteralExpression) { return true; } From 9344bd0a397e74246e657ec466548067de7fe59d Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 7 Jul 2015 13:25:53 -0700 Subject: [PATCH 03/29] Add tests --- ...ifierOnClassDeclarationMemberInFunction.js | 25 +++++++++++++++++++ ...OnClassDeclarationMemberInFunction.symbols | 18 +++++++++++++ ...erOnClassDeclarationMemberInFunction.types | 19 ++++++++++++++ ...difierOnClassExpressionMemberInFunction.js | 25 +++++++++++++++++++ ...rOnClassExpressionMemberInFunction.symbols | 19 ++++++++++++++ ...ierOnClassExpressionMemberInFunction.types | 22 ++++++++++++++++ ...ifierOnClassDeclarationMemberInFunction.ts | 9 +++++++ ...difierOnClassExpressionMemberInFunction.ts | 10 ++++++++ 8 files changed, 147 insertions(+) create mode 100644 tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.js create mode 100644 tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.symbols create mode 100644 tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.types create mode 100644 tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js create mode 100644 tests/baselines/reference/modifierOnClassExpressionMemberInFunction.symbols create mode 100644 tests/baselines/reference/modifierOnClassExpressionMemberInFunction.types create mode 100644 tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts create mode 100644 tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts diff --git a/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.js b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.js new file mode 100644 index 00000000000..d571a4143ee --- /dev/null +++ b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.js @@ -0,0 +1,25 @@ +//// [modifierOnClassDeclarationMemberInFunction.ts] + +function f() { + class C { + public baz = 1; + static foo() { } + public bar() { } + } +} + +//// [modifierOnClassDeclarationMemberInFunction.js] +function f() { + var C = (function () { + function C() { + this.baz = 1; + } + C.foo = function () { }; + C.prototype.bar = function () { }; + return C; + })(); +} + + +//// [modifierOnClassDeclarationMemberInFunction.d.ts] +declare function f(): void; diff --git a/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.symbols b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.symbols new file mode 100644 index 00000000000..a411bee09cb --- /dev/null +++ b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts === + +function f() { +>f : Symbol(f, Decl(modifierOnClassDeclarationMemberInFunction.ts, 0, 0)) + + class C { +>C : Symbol(C, Decl(modifierOnClassDeclarationMemberInFunction.ts, 1, 14)) + + public baz = 1; +>baz : Symbol(baz, Decl(modifierOnClassDeclarationMemberInFunction.ts, 2, 13)) + + static foo() { } +>foo : Symbol(C.foo, Decl(modifierOnClassDeclarationMemberInFunction.ts, 3, 23)) + + public bar() { } +>bar : Symbol(bar, Decl(modifierOnClassDeclarationMemberInFunction.ts, 4, 24)) + } +} diff --git a/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.types b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.types new file mode 100644 index 00000000000..dfd482a6bc8 --- /dev/null +++ b/tests/baselines/reference/modifierOnClassDeclarationMemberInFunction.types @@ -0,0 +1,19 @@ +=== tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts === + +function f() { +>f : () => void + + class C { +>C : C + + public baz = 1; +>baz : number +>1 : number + + static foo() { } +>foo : () => void + + public bar() { } +>bar : () => void + } +} diff --git a/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js new file mode 100644 index 00000000000..e43e8dd8203 --- /dev/null +++ b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js @@ -0,0 +1,25 @@ +//// [modifierOnClassExpressionMemberInFunction.ts] + +function g() { + var x = class C { + public prop1 = 1; + private foo() { } + static prop2 = 43; + } +} + +//// [modifierOnClassExpressionMemberInFunction.js] +function g() { + var x = (function () { + function C() { + this.prop1 = 1; + } + C.prototype.foo = function () { }; + C.prop2 = 43; + return C; + })(); +} + + +//// [modifierOnClassExpressionMemberInFunction.d.ts] +declare function g(): void; diff --git a/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.symbols b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.symbols new file mode 100644 index 00000000000..d603d96dcda --- /dev/null +++ b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts === + +function g() { +>g : Symbol(g, Decl(modifierOnClassExpressionMemberInFunction.ts, 0, 0)) + + var x = class C { +>x : Symbol(x, Decl(modifierOnClassExpressionMemberInFunction.ts, 2, 7)) +>C : Symbol(C, Decl(modifierOnClassExpressionMemberInFunction.ts, 2, 11)) + + public prop1 = 1; +>prop1 : Symbol(C.prop1, Decl(modifierOnClassExpressionMemberInFunction.ts, 2, 21)) + + private foo() { } +>foo : Symbol(C.foo, Decl(modifierOnClassExpressionMemberInFunction.ts, 3, 25)) + + static prop2 = 43; +>prop2 : Symbol(C.prop2, Decl(modifierOnClassExpressionMemberInFunction.ts, 4, 25)) + } +} diff --git a/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.types b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.types new file mode 100644 index 00000000000..87a200ee56e --- /dev/null +++ b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.types @@ -0,0 +1,22 @@ +=== tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts === + +function g() { +>g : () => void + + var x = class C { +>x : typeof C +>class C { public prop1 = 1; private foo() { } static prop2 = 43; } : typeof C +>C : typeof C + + public prop1 = 1; +>prop1 : number +>1 : number + + private foo() { } +>foo : () => void + + static prop2 = 43; +>prop2 : number +>43 : number + } +} diff --git a/tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts b/tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts new file mode 100644 index 00000000000..f0d7c355e3b --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/modifierOnClassDeclarationMemberInFunction.ts @@ -0,0 +1,9 @@ +// @declaration: true + +function f() { + class C { + public baz = 1; + static foo() { } + public bar() { } + } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts b/tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts new file mode 100644 index 00000000000..100c04a1d31 --- /dev/null +++ b/tests/cases/conformance/classes/classExpressions/modifierOnClassExpressionMemberInFunction.ts @@ -0,0 +1,10 @@ +// @declaration: true +// @declaration: true + +function g() { + var x = class C { + public prop1 = 1; + private foo() { } + static prop2 = 43; + } +} \ No newline at end of file From d6dc67d38fbdf8a3184b3422b9ccf0c0cbd9967e Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 14:11:18 -0700 Subject: [PATCH 04/29] Add window.URL --- src/lib/dom.generated.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 84e959caef8..f6a8471b925 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -11984,6 +11984,7 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window toolbar: BarProp; top: Window; window: Window; + URL: URL; alert(message?: any): void; blur(): void; cancelAnimationFrame(handle: number): void; @@ -12798,6 +12799,7 @@ declare var styleMedia: StyleMedia; declare var toolbar: BarProp; declare var top: Window; declare var window: Window; +declare var URL: URL; declare function alert(message?: any): void; declare function blur(): void; declare function cancelAnimationFrame(handle: number): void; From 99fc99f3bcbc123b7c37be05a4be7ac25e929fd7 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 14:27:57 -0700 Subject: [PATCH 05/29] Improved fix from @JsonFreeman --- src/compiler/checker.ts | 10 +++---- .../reference/tsxAttributeResolution9.symbols | 30 ++++++++++--------- .../reference/tsxAttributeResolution9.types | 8 +++-- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b910dc3306b..842b6dcd550 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7096,18 +7096,18 @@ namespace ts { // Look up the value in the current scope if (node.tagName.kind === SyntaxKind.Identifier) { let tag = node.tagName; - valueSymbol = resolveName(tag, tag.text, SymbolFlags.Value, Diagnostics.Cannot_find_name_0, tag.text); + let maybeExportSymbol = getResolvedSymbol(node.tagName); + let valueDecl = maybeExportSymbol.valueDeclaration; + + valueSymbol = (valueDecl && valueDecl.localSymbol) || maybeExportSymbol; } else { valueSymbol = checkQualifiedName(node.tagName).symbol; } if (valueSymbol && valueSymbol !== unknownSymbol) { - let symbolLinks = getSymbolLinks(valueSymbol); - if (symbolLinks) { - symbolLinks.referenced = true; - } links.jsxFlags |= JsxFlags.ClassElement; + getSymbolLinks(valueSymbol).referenced = true; } return valueSymbol || unknownSymbol; diff --git a/tests/baselines/reference/tsxAttributeResolution9.symbols b/tests/baselines/reference/tsxAttributeResolution9.symbols index cbb30864c81..081482d5d47 100644 --- a/tests/baselines/reference/tsxAttributeResolution9.symbols +++ b/tests/baselines/reference/tsxAttributeResolution9.symbols @@ -1,45 +1,47 @@ -=== tests/cases/conformance/jsx/tsxAttributeResolution9.tsx === +=== tests/cases/conformance/jsx/react.d.ts === + declare module JSX { ->JSX : Symbol(JSX, Decl(tsxAttributeResolution9.tsx, 0, 0)) +>JSX : Symbol(JSX, Decl(react.d.ts, 0, 0)) interface Element { } ->Element : Symbol(Element, Decl(tsxAttributeResolution9.tsx, 0, 20)) +>Element : Symbol(Element, Decl(react.d.ts, 1, 20)) interface IntrinsicElements { ->IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxAttributeResolution9.tsx, 1, 22)) +>IntrinsicElements : Symbol(IntrinsicElements, Decl(react.d.ts, 2, 22)) } interface ElementAttributesProperty { ->ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(tsxAttributeResolution9.tsx, 3, 2)) +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(react.d.ts, 4, 2)) props; ->props : Symbol(props, Decl(tsxAttributeResolution9.tsx, 4, 38)) +>props : Symbol(props, Decl(react.d.ts, 5, 38)) } } interface Props { ->Props : Symbol(Props, Decl(tsxAttributeResolution9.tsx, 7, 1)) +>Props : Symbol(Props, Decl(react.d.ts, 8, 1)) foo: string; ->foo : Symbol(foo, Decl(tsxAttributeResolution9.tsx, 9, 17)) +>foo : Symbol(foo, Decl(react.d.ts, 10, 17)) } +=== tests/cases/conformance/jsx/file.tsx === export class MyComponent { ->MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 0, 0)) render() { ->render : Symbol(render, Decl(tsxAttributeResolution9.tsx, 13, 26)) +>render : Symbol(render, Decl(file.tsx, 0, 26)) } props: { foo: string; } ->props : Symbol(props, Decl(tsxAttributeResolution9.tsx, 15, 3)) ->foo : Symbol(foo, Decl(tsxAttributeResolution9.tsx, 17, 10)) +>props : Symbol(props, Decl(file.tsx, 2, 3)) +>foo : Symbol(foo, Decl(file.tsx, 4, 10)) } ; // ok ->MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 0, 0)) >foo : Symbol(unknown) ; // should be an error ->MyComponent : Symbol(MyComponent, Decl(tsxAttributeResolution9.tsx, 11, 1)) +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 0, 0)) >foo : Symbol(unknown) diff --git a/tests/baselines/reference/tsxAttributeResolution9.types b/tests/baselines/reference/tsxAttributeResolution9.types index aab3806a5f0..1b2c6d42389 100644 --- a/tests/baselines/reference/tsxAttributeResolution9.types +++ b/tests/baselines/reference/tsxAttributeResolution9.types @@ -1,4 +1,5 @@ -=== tests/cases/conformance/jsx/tsxAttributeResolution9.tsx === +=== tests/cases/conformance/jsx/react.d.ts === + declare module JSX { >JSX : any @@ -23,6 +24,7 @@ interface Props { >foo : string } +=== tests/cases/conformance/jsx/file.tsx === export class MyComponent { >MyComponent : MyComponent @@ -36,12 +38,12 @@ export class MyComponent { } ; // ok -> : any +> : JSX.Element >MyComponent : typeof MyComponent >foo : any ; // should be an error -> : any +> : JSX.Element >MyComponent : typeof MyComponent >foo : any From 70c4f08b10c93049d7ca131f2a24eccd9601c8ab Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 14:30:38 -0700 Subject: [PATCH 06/29] Changed the return type of several well-known functions to NodeList --- src/lib/dom.generated.d.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 84e959caef8..36d1588636d 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -2254,12 +2254,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param elementId String that specifies the ID value. Case-insensitive. */ getElementById(elementId: string): HTMLElement; - getElementsByClassName(classNames: string): NodeList; + getElementsByClassName(classNames: string): NodeList; /** * Gets a collection of objects based on the value of the NAME or ID attribute. * @param elementName Gets a collection of objects based on the value of the NAME or ID attribute. */ - getElementsByName(elementName: string): NodeList; + getElementsByName(elementName: string): NodeList; /** * Retrieves a collection of objects based on the specified element name. * @param name Specifies the name of an element. @@ -2437,8 +2437,8 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven getElementsByTagName(tagname: "wbr"): NodeListOf; getElementsByTagName(tagname: "x-ms-webview"): NodeListOf; getElementsByTagName(tagname: "xmp"): NodeListOf; - getElementsByTagName(tagname: string): NodeList; - getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; + getElementsByTagName(tagname: string): NodeList; + getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; /** * Returns an object representing the current selection of the document that is loaded into the object displaying a webpage. */ @@ -2890,8 +2890,8 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec getElementsByTagName(name: "wbr"): NodeListOf; getElementsByTagName(name: "x-ms-webview"): NodeListOf; getElementsByTagName(name: "xmp"): NodeListOf; - getElementsByTagName(name: string): NodeList; - getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; + getElementsByTagName(name: string): NodeList; + getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; hasAttribute(name: string): boolean; hasAttributeNS(namespaceURI: string, localName: string): boolean; msGetRegionContent(): MSRangeCollection; @@ -3903,7 +3903,7 @@ interface HTMLElement extends Element { contains(child: HTMLElement): boolean; dragDrop(): boolean; focus(): void; - getElementsByClassName(classNames: string): NodeList; + getElementsByClassName(classNames: string): NodeList; insertAdjacentElement(position: string, insertedElement: Element): Element; insertAdjacentHTML(where: string, html: string): void; insertAdjacentText(where: string, text: string): void; @@ -12487,7 +12487,7 @@ interface NavigatorStorageUtils { interface NodeSelector { querySelector(selectors: string): Element; - querySelectorAll(selectors: string): NodeList; + querySelectorAll(selectors: string): NodeList; } interface RandomSource { From 3ccaa0ee261c70cd32e31af3e458c44a23fe6b10 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 14:33:59 -0700 Subject: [PATCH 07/29] Cleanup --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 842b6dcd550..da7ac5844b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7096,9 +7096,8 @@ namespace ts { // Look up the value in the current scope if (node.tagName.kind === SyntaxKind.Identifier) { let tag = node.tagName; - let maybeExportSymbol = getResolvedSymbol(node.tagName); + let maybeExportSymbol = getResolvedSymbol(tag); let valueDecl = maybeExportSymbol.valueDeclaration; - valueSymbol = (valueDecl && valueDecl.localSymbol) || maybeExportSymbol; } else { From 33df79d11ec2d9ca5e8e0bb13ff29cf96c96888e Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 14:40:08 -0700 Subject: [PATCH 08/29] Correct "NodeList" to "NodeListOf" --- src/lib/dom.generated.d.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 36d1588636d..8d5f8ac9254 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -2254,12 +2254,12 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven * @param elementId String that specifies the ID value. Case-insensitive. */ getElementById(elementId: string): HTMLElement; - getElementsByClassName(classNames: string): NodeList; + getElementsByClassName(classNames: string): NodeListOf; /** * Gets a collection of objects based on the value of the NAME or ID attribute. * @param elementName Gets a collection of objects based on the value of the NAME or ID attribute. */ - getElementsByName(elementName: string): NodeList; + getElementsByName(elementName: string): NodeListOf; /** * Retrieves a collection of objects based on the specified element name. * @param name Specifies the name of an element. @@ -2437,8 +2437,8 @@ interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEven getElementsByTagName(tagname: "wbr"): NodeListOf; getElementsByTagName(tagname: "x-ms-webview"): NodeListOf; getElementsByTagName(tagname: "xmp"): NodeListOf; - getElementsByTagName(tagname: string): NodeList; - getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; + getElementsByTagName(tagname: string): NodeListOf; + getElementsByTagNameNS(namespaceURI: string, localName: string): NodeListOf; /** * Returns an object representing the current selection of the document that is loaded into the object displaying a webpage. */ @@ -2890,8 +2890,8 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec getElementsByTagName(name: "wbr"): NodeListOf; getElementsByTagName(name: "x-ms-webview"): NodeListOf; getElementsByTagName(name: "xmp"): NodeListOf; - getElementsByTagName(name: string): NodeList; - getElementsByTagNameNS(namespaceURI: string, localName: string): NodeList; + getElementsByTagName(name: string): NodeListOf; + getElementsByTagNameNS(namespaceURI: string, localName: string): NodeListOf; hasAttribute(name: string): boolean; hasAttributeNS(namespaceURI: string, localName: string): boolean; msGetRegionContent(): MSRangeCollection; @@ -3903,7 +3903,7 @@ interface HTMLElement extends Element { contains(child: HTMLElement): boolean; dragDrop(): boolean; focus(): void; - getElementsByClassName(classNames: string): NodeList; + getElementsByClassName(classNames: string): NodeListOf; insertAdjacentElement(position: string, insertedElement: Element): Element; insertAdjacentHTML(where: string, html: string): void; insertAdjacentText(where: string, text: string): void; @@ -12487,7 +12487,7 @@ interface NavigatorStorageUtils { interface NodeSelector { querySelector(selectors: string): Element; - querySelectorAll(selectors: string): NodeList; + querySelectorAll(selectors: string): NodeListOf; } interface RandomSource { From 6e332cf26697f4dbb557ce2199ab88ac4b612b78 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 15:45:35 -0700 Subject: [PATCH 09/29] Remove file that shouldn't have been in this branch --- .../tsxAttributeResolution9.errors.txt | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 tests/baselines/reference/tsxAttributeResolution9.errors.txt diff --git a/tests/baselines/reference/tsxAttributeResolution9.errors.txt b/tests/baselines/reference/tsxAttributeResolution9.errors.txt deleted file mode 100644 index c25532eaa0a..00000000000 --- a/tests/baselines/reference/tsxAttributeResolution9.errors.txt +++ /dev/null @@ -1,31 +0,0 @@ -tests/cases/conformance/jsx/file.tsx(9,14): error TS2322: Type 'number' is not assignable to type 'string'. - - -==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== - - declare module JSX { - interface Element { } - interface IntrinsicElements { - } - interface ElementAttributesProperty { - props; - } - } - - interface Props { - foo: string; - } - -==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== - export class MyComponent { - render() { - } - - props: { foo: string; } - } - - ; // ok - ; // should be an error - ~~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'string'. - \ No newline at end of file From 8f3bce121d6f429ea90b121346fe2dc39542a5d3 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 16:22:04 -0700 Subject: [PATCH 10/29] Actually fix the bug this time. --- src/compiler/checker.ts | 5 ++- .../tsxAttributeResolution9.errors.txt | 31 ------------------- 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 tests/baselines/reference/tsxAttributeResolution9.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7e631ff5bce..1edd2a7a920 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7096,9 +7096,8 @@ namespace ts { // Look up the value in the current scope if (node.tagName.kind === SyntaxKind.Identifier) { let tag = node.tagName; - let maybeExportSymbol = getResolvedSymbol(tag); - let valueDecl = maybeExportSymbol.valueDeclaration; - valueSymbol = (valueDecl && valueDecl.localSymbol) || maybeExportSymbol; + let sym = getResolvedSymbol(tag); + valueSymbol = sym.exportSymbol || sym; } else { valueSymbol = checkQualifiedName(node.tagName).symbol; diff --git a/tests/baselines/reference/tsxAttributeResolution9.errors.txt b/tests/baselines/reference/tsxAttributeResolution9.errors.txt deleted file mode 100644 index c25532eaa0a..00000000000 --- a/tests/baselines/reference/tsxAttributeResolution9.errors.txt +++ /dev/null @@ -1,31 +0,0 @@ -tests/cases/conformance/jsx/file.tsx(9,14): error TS2322: Type 'number' is not assignable to type 'string'. - - -==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== - - declare module JSX { - interface Element { } - interface IntrinsicElements { - } - interface ElementAttributesProperty { - props; - } - } - - interface Props { - foo: string; - } - -==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== - export class MyComponent { - render() { - } - - props: { foo: string; } - } - - ; // ok - ; // should be an error - ~~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'string'. - \ No newline at end of file From cdc999a6c51e819e7962f5acfd0c2bbf73f2814e Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 7 Jul 2015 16:26:48 -0700 Subject: [PATCH 11/29] Only check if method declaration has modifier when method is declared in object literal expression --- src/compiler/checker.ts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7083feabb2c..f4bbc71793e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11444,9 +11444,10 @@ namespace ts { forEach(node.declarationList.declarations, checkSourceElement); } - function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node: Node) { + function checkGrammarDisallowedModifiersOnMethodInObjectLiteralExpression(node: Node) { if (node.modifiers) { - if (inObjectLiteralExpression(node)) { + if (node.parent.kind === SyntaxKind.ObjectLiteralExpression){ + // If this method declaration is a property of object-literal-expression if (isAsyncFunctionLike(node)) { if (node.modifiers.length > 1) { return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); @@ -11459,18 +11460,6 @@ namespace ts { } } - function inObjectLiteralExpression(node: Node) { - while (node) { - if (node.kind === SyntaxKind.ObjectLiteralExpression) { - return true; - } - - node = node.parent; - } - - return false; - } - function checkExpressionStatement(node: ExpressionStatement) { // Grammar checking checkGrammarStatementInAmbientContext(node); @@ -15026,7 +15015,7 @@ namespace ts { } function checkGrammarMethod(node: MethodDeclaration) { - if (checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + if (checkGrammarDisallowedModifiersOnMethodInObjectLiteralExpression(node) || checkGrammarFunctionLikeDeclaration(node) || checkGrammarForGenerator(node)) { return true; From 91a138e395d547323dda6849634f800f3b4e129b Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 16:49:00 -0700 Subject: [PATCH 12/29] Move className and id from HTMLElement to Element --- src/lib/dom.generated.d.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 84e959caef8..804568666af 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -2711,6 +2711,8 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec scrollTop: number; scrollWidth: number; tagName: string; + id: string; + className: string; getAttribute(name?: string): string; getAttributeNS(namespaceURI: string, localName: string): string; getAttributeNode(name: string): Attr; @@ -3809,14 +3811,12 @@ declare var HTMLDocument: { interface HTMLElement extends Element { accessKey: string; children: HTMLCollection; - className: string; contentEditable: string; dataset: DOMStringMap; dir: string; draggable: boolean; hidden: boolean; hideFocus: boolean; - id: string; innerHTML: string; innerText: string; isContentEditable: boolean; @@ -12535,7 +12535,6 @@ interface SVGLocatable { } interface SVGStylable { - className: SVGAnimatedString; style: CSSStyleDeclaration; } From 3e57af13b93e082b05b3c1cbf21ef2e7516e5591 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 7 Jul 2015 17:04:03 -0700 Subject: [PATCH 13/29] Add missed file --- .../tsxAttributeResolution9.errors.txt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/baselines/reference/tsxAttributeResolution9.errors.txt diff --git a/tests/baselines/reference/tsxAttributeResolution9.errors.txt b/tests/baselines/reference/tsxAttributeResolution9.errors.txt new file mode 100644 index 00000000000..c25532eaa0a --- /dev/null +++ b/tests/baselines/reference/tsxAttributeResolution9.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/jsx/file.tsx(9,14): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsx/react.d.ts (0 errors) ==== + + declare module JSX { + interface Element { } + interface IntrinsicElements { + } + interface ElementAttributesProperty { + props; + } + } + + interface Props { + foo: string; + } + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + export class MyComponent { + render() { + } + + props: { foo: string; } + } + + ; // ok + ; // should be an error + ~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + \ No newline at end of file From 90779a9d87bd3f94a0c2c13dcc83487b28993f83 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 17:13:52 -0700 Subject: [PATCH 14/29] Fix the definition of interface ErrorEventHandler --- src/lib/dom.generated.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 84e959caef8..e4e250a52ef 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -12622,7 +12622,7 @@ interface EventListenerObject { declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject; interface ErrorEventHandler { - (event: Event | string, source?: string, fileno?: number, columnNumber?: number): void; + (message: string, filename?: string, lineno?: number, colno?: number, error?:Error): void; } interface PositionCallback { (position: Position): void; From 869de7391ea1c5ed152aeb44314444cf19c8d254 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 7 Jul 2015 17:19:34 -0700 Subject: [PATCH 15/29] Fix FormData constructor --- src/lib/dom.generated.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 84e959caef8..4cff6e7f7b3 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -3072,7 +3072,7 @@ interface FormData { declare var FormData: { prototype: FormData; - new(): FormData; + new (form?: HTMLFormElement): FormData; } interface GainNode extends AudioNode { From e0e9bcff466b3cbb2cec920702e29f028b4a2cb7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 7 Jul 2015 17:44:22 -0700 Subject: [PATCH 16/29] Don't call push.apply, it can stack overflow with large arrays. --- src/compiler/checker.ts | 2 +- src/services/navigationBar.ts | 4 ++-- src/services/services.ts | 22 +++++++++++----------- src/services/signatureHelp.ts | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3ef2c6ada2a..e8ac59449d9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3305,7 +3305,7 @@ namespace ts { let declarations: Declaration[] = []; for (let prop of props) { if (prop.declarations) { - declarations.push.apply(declarations, prop.declarations); + addRange(declarations, prop.declarations); } propTypes.push(getTypeOfSymbol(prop)); } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index ead9bc519ce..e822052a5b2 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -228,7 +228,7 @@ namespace ts.NavigationBar { function merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { // First, add any spans in the source to the target. - target.spans.push.apply(target.spans, source.spans); + addRange(target.spans, source.spans); if (source.childItems) { if (!target.childItems) { @@ -465,7 +465,7 @@ namespace ts.NavigationBar { // are not properties will be filtered out later by createChildItem. let nodes: Node[] = removeDynamicallyNamedProperties(node); if (constructor) { - nodes.push.apply(nodes, filter(constructor.parameters, p => !isBindingPattern(p.name))); + addRange(nodes, filter(constructor.parameters, p => !isBindingPattern(p.name))); } childItems = getItemsWorker(sortNodes(nodes), createChildItem); diff --git a/src/services/services.ts b/src/services/services.ts index 9996a2ac5fa..fe4f376cbdf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -345,7 +345,7 @@ namespace ts { ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), jsDocCommentTextRange => { let cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); if (cleanedParamJsDocComment) { - jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment); + addRange(jsDocCommentParts, cleanedParamJsDocComment); } }); } @@ -365,7 +365,7 @@ namespace ts { declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, sourceFileOfDeclaration), jsDocCommentTextRange => { let cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); if (cleanedJsDocComment) { - jsDocCommentParts.push.apply(jsDocCommentParts, cleanedJsDocComment); + addRange(jsDocCommentParts, cleanedJsDocComment); } }); } @@ -3812,7 +3812,7 @@ namespace ts { displayParts.push(spacePart()); } if (!(type.flags & TypeFlags.Anonymous)) { - displayParts.push.apply(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); } addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); break; @@ -3873,7 +3873,7 @@ namespace ts { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + addRange(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); @@ -3919,7 +3919,7 @@ namespace ts { else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { addFullSymbolName(signatureDeclaration.symbol); } - displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); } } if (symbolFlags & SymbolFlags.EnumMember) { @@ -3980,10 +3980,10 @@ namespace ts { let typeParameterParts = mapToDisplayParts(writer => { typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); }); - displayParts.push.apply(displayParts, typeParameterParts); + addRange(displayParts, typeParameterParts); } else { - displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); + addRange(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); } } else if (symbolFlags & SymbolFlags.Function || @@ -4017,7 +4017,7 @@ namespace ts { function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) { let fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing); - displayParts.push.apply(displayParts, fullSymbolDisplayParts); + addRange(displayParts, fullSymbolDisplayParts); } function addPrefixForAnyFunctionOrVar(symbol: Symbol, symbolKind: string) { @@ -4047,7 +4047,7 @@ namespace ts { } function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags?: TypeFormatFlags) { - displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + addRange(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); if (allSignatures.length > 1) { displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -4064,7 +4064,7 @@ namespace ts { let typeParameterParts = mapToDisplayParts(writer => { typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); }); - displayParts.push.apply(displayParts, typeParameterParts); + addRange(displayParts, typeParameterParts); } } @@ -5578,7 +5578,7 @@ namespace ts { // type to the search set if (isNameOfPropertyAssignment(location)) { forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => { - result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol)); + addRange(result, typeChecker.getRootSymbols(contextualSymbol)); }); /* Because in short-hand property assignment, location has two meaning : property name and as value of the property diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 44b022a7b12..f44ebade2a7 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -550,7 +550,7 @@ namespace ts.SignatureHelp { let suffixDisplayParts: SymbolDisplayPart[] = []; if (callTargetDisplayParts) { - prefixDisplayParts.push.apply(prefixDisplayParts, callTargetDisplayParts); + addRange(prefixDisplayParts, callTargetDisplayParts); } if (isTypeParameterList) { @@ -560,12 +560,12 @@ namespace ts.SignatureHelp { suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); let parameterParts = mapToDisplayParts(writer => typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); - suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts); + addRange(suffixDisplayParts, parameterParts); } else { let typeParameterParts = mapToDisplayParts(writer => typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); - prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts); + addRange(prefixDisplayParts, typeParameterParts); prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); let parameters = candidateSignature.parameters; @@ -575,7 +575,7 @@ namespace ts.SignatureHelp { let returnTypeParts = mapToDisplayParts(writer => typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); - suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts); + addRange(suffixDisplayParts, returnTypeParts); return { isVariadic: candidateSignature.hasRestParameter, From 8e15a42632aa68153b85632cff6678216eaab94d Mon Sep 17 00:00:00 2001 From: Yui T Date: Wed, 8 Jul 2015 13:56:27 -0700 Subject: [PATCH 17/29] Address code review --- src/compiler/checker.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f4bbc71793e..0b577cc12fd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11444,19 +11444,17 @@ namespace ts { forEach(node.declarationList.declarations, checkSourceElement); } - function checkGrammarDisallowedModifiersOnMethodInObjectLiteralExpression(node: Node) { - if (node.modifiers) { - if (node.parent.kind === SyntaxKind.ObjectLiteralExpression){ - // If this method declaration is a property of object-literal-expression - if (isAsyncFunctionLike(node)) { - if (node.modifiers.length > 1) { - return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); - } - } - else { + function checkGrammarDisallowedModifiersOnObjectLiteralExpressionMethod(node: Node) { + // We only disallow modifier on a method declaration if it is a property of object-literal-expression + if (node.modifiers && node.parent.kind === SyntaxKind.ObjectLiteralExpression){ + if (isAsyncFunctionLike(node)) { + if (node.modifiers.length > 1) { return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); } } + else { + return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); + } } } @@ -15015,7 +15013,7 @@ namespace ts { } function checkGrammarMethod(node: MethodDeclaration) { - if (checkGrammarDisallowedModifiersOnMethodInObjectLiteralExpression(node) || + if (checkGrammarDisallowedModifiersOnObjectLiteralExpressionMethod(node) || checkGrammarFunctionLikeDeclaration(node) || checkGrammarForGenerator(node)) { return true; From 98e6db47982f9024e1a04cacc15ade7f31f49159 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 9 Jul 2015 11:16:36 +0800 Subject: [PATCH 18/29] Fixes fourslash code formatting --- src/harness/fourslashRunner.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/harness/fourslashRunner.ts b/src/harness/fourslashRunner.ts index d11c5e639e5..0db01c30f32 100644 --- a/src/harness/fourslashRunner.ts +++ b/src/harness/fourslashRunner.ts @@ -35,9 +35,9 @@ class FourSlashRunner extends RunnerBase { this.tests = this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false }); } - this.tests.forEach((fn: string) => { - describe(fn, () => { - fn = ts.normalizeSlashes(fn); + this.tests.forEach((fn: string) => { + describe(fn, () => { + fn = ts.normalizeSlashes(fn); var justName = fn.replace(/^.*[\\\/]/, ''); // Convert to relative path @@ -45,7 +45,7 @@ class FourSlashRunner extends RunnerBase { if (testIndex >= 0) fn = fn.substr(testIndex); if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) { - it(this.testSuiteName + ' test ' + justName + ' runs correctly',() => { + it(this.testSuiteName + ' test ' + justName + ' runs correctly', () => { FourSlash.runFourSlashTest(this.basePath, this.testType, fn); }); } From 951084fc853107b4d8e3dd616545fb34fba52ac3 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 7 Jul 2015 11:01:49 +0800 Subject: [PATCH 19/29] Fixes emit of type predicated in delcaration files --- src/compiler/declarationEmitter.ts | 46 +++++++++++++---------- tests/cases/compiler/declFileFunctions.ts | 4 ++ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 8c012f2678e..3db032b8d0d 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -188,7 +188,7 @@ namespace ts { if (!moduleElementEmitInfo && asynchronousSubModuleDeclarationEmitInfo) { moduleElementEmitInfo = forEach(asynchronousSubModuleDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined); } - + // If the alias was marked as not visible when we saw its declaration, we would have saved the aliasEmitInfo, but if we haven't yet visited the alias declaration // then we don't need to write it at this point. We will write it when we actually see its declaration // Eg. @@ -198,7 +198,7 @@ namespace ts { // we would write alias foo declaration when we visit it since it would now be marked as visible if (moduleElementEmitInfo) { if (moduleElementEmitInfo.node.kind === SyntaxKind.ImportDeclaration) { - // we have to create asynchronous output only after we have collected complete information + // we have to create asynchronous output only after we have collected complete information // because it is possible to enable multiple bindings as asynchronously visible moduleElementEmitInfo.isVisible = true; } @@ -353,6 +353,21 @@ namespace ts { return emitEntityName(type); case SyntaxKind.QualifiedName: return emitEntityName(type); + case SyntaxKind.TypePredicate: + return emitTypePredicate(type); + } + + function writeEntityName(entityName: EntityName | Expression) { + if (entityName.kind === SyntaxKind.Identifier) { + writeTextOfNode(currentSourceFile, entityName); + } + else { + let left = entityName.kind === SyntaxKind.QualifiedName ? (entityName).left : (entityName).expression; + let right = entityName.kind === SyntaxKind.QualifiedName ? (entityName).right : (entityName).name; + writeEntityName(left); + write("."); + writeTextOfNode(currentSourceFile, right); + } } function emitEntityName(entityName: EntityName | PropertyAccessExpression) { @@ -362,19 +377,6 @@ namespace ts { handleSymbolAccessibilityError(visibilityResult); writeEntityName(entityName); - - function writeEntityName(entityName: EntityName | Expression) { - if (entityName.kind === SyntaxKind.Identifier) { - writeTextOfNode(currentSourceFile, entityName); - } - else { - let left = entityName.kind === SyntaxKind.QualifiedName ? (entityName).left : (entityName).expression; - let right = entityName.kind === SyntaxKind.QualifiedName ? (entityName).right : (entityName).name; - writeEntityName(left); - write("."); - writeTextOfNode(currentSourceFile, right); - } - } } function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { @@ -398,6 +400,12 @@ namespace ts { } } + function emitTypePredicate(type: TypePredicateNode) { + writeEntityName(type.parameterName); + write(" is "); + emitType(type.type); + } + function emitTypeQuery(type: TypeQueryNode) { write("typeof "); emitEntityName(type.exprName); @@ -600,7 +608,7 @@ namespace ts { } function writeImportEqualsDeclaration(node: ImportEqualsDeclaration) { - // note usage of writer. methods instead of aliases created, just to make sure we are using + // note usage of writer. methods instead of aliases created, just to make sure we are using // correct writer especially to handle asynchronous alias writing emitJsDocComments(node); if (node.flags & NodeFlags.Export) { @@ -642,7 +650,7 @@ namespace ts { function writeImportDeclaration(node: ImportDeclaration) { if (!node.importClause && !(node.flags & NodeFlags.Export)) { - // do not write non-exported import declarations that don't have import clauses + // do not write non-exported import declarations that don't have import clauses return; } emitJsDocComments(node); @@ -1517,7 +1525,7 @@ namespace ts { } } } - } + } } function emitNode(node: Node) { @@ -1577,7 +1585,7 @@ namespace ts { referencePathsOutput += "/// " + newLine; } } - + /* @internal */ export function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) { let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile); diff --git a/tests/cases/compiler/declFileFunctions.ts b/tests/cases/compiler/declFileFunctions.ts index e7ce3d07f82..36972d427f0 100644 --- a/tests/cases/compiler/declFileFunctions.ts +++ b/tests/cases/compiler/declFileFunctions.ts @@ -28,6 +28,10 @@ export function fooWithSingleOverload(a: any) { return a; } +export function fooWithTypePredicate(a: any): a is number { + return true; +} + /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { } From 08a774425452b7a24219fbdf3564b8642ce5f20c Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Tue, 7 Jul 2015 11:11:56 +0800 Subject: [PATCH 20/29] Accepts baselines --- .../baselines/reference/declFileFunctions.js | 9 ++++ .../reference/declFileFunctions.symbols | 44 +++++++++++-------- .../reference/declFileFunctions.types | 9 ++++ 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/tests/baselines/reference/declFileFunctions.js b/tests/baselines/reference/declFileFunctions.js index da1917163e1..d3debf4d50c 100644 --- a/tests/baselines/reference/declFileFunctions.js +++ b/tests/baselines/reference/declFileFunctions.js @@ -26,6 +26,10 @@ export function fooWithSingleOverload(a: any) { return a; } +export function fooWithTypePredicate(a: any): a is number { + return true; +} + /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { } @@ -92,6 +96,10 @@ function fooWithSingleOverload(a) { return a; } exports.fooWithSingleOverload = fooWithSingleOverload; +function fooWithTypePredicate(a) { + return true; +} +exports.fooWithTypePredicate = fooWithTypePredicate; /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { } @@ -144,6 +152,7 @@ export declare function fooWithRestParameters(a: string, ...rests: string[]): st export declare function fooWithOverloads(a: string): string; export declare function fooWithOverloads(a: number): number; export declare function fooWithSingleOverload(a: string): string; +export declare function fooWithTypePredicate(a: any): a is number; //// [declFileFunctions_1.d.ts] /** This comment should appear for foo*/ declare function globalfoo(): void; diff --git a/tests/baselines/reference/declFileFunctions.symbols b/tests/baselines/reference/declFileFunctions.symbols index ff04d211557..1d62cc29d28 100644 --- a/tests/baselines/reference/declFileFunctions.symbols +++ b/tests/baselines/reference/declFileFunctions.symbols @@ -57,49 +57,57 @@ export function fooWithSingleOverload(a: any) { >a : Symbol(a, Decl(declFileFunctions_0.ts, 21, 38)) } +export function fooWithTypePredicate(a: any): a is number { +>fooWithTypePredicate : Symbol(fooWithTypePredicate, Decl(declFileFunctions_0.ts, 23, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 25, 37)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 25, 37)) + + return true; +} + /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { ->nonExportedFoo : Symbol(nonExportedFoo, Decl(declFileFunctions_0.ts, 23, 1)) +>nonExportedFoo : Symbol(nonExportedFoo, Decl(declFileFunctions_0.ts, 27, 1)) } /** This is comment for function signature*/ function nonExportedFooWithParameters(/** this is comment about a*/a: string, ->nonExportedFooWithParameters : Symbol(nonExportedFooWithParameters, Decl(declFileFunctions_0.ts, 27, 1)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 29, 38)) +>nonExportedFooWithParameters : Symbol(nonExportedFooWithParameters, Decl(declFileFunctions_0.ts, 31, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 33, 38)) /** this is comment for b*/ b: number) { ->b : Symbol(b, Decl(declFileFunctions_0.ts, 29, 77)) +>b : Symbol(b, Decl(declFileFunctions_0.ts, 33, 77)) var d = a; ->d : Symbol(d, Decl(declFileFunctions_0.ts, 32, 7)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 29, 38)) +>d : Symbol(d, Decl(declFileFunctions_0.ts, 36, 7)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 33, 38)) } function nonExportedFooWithRestParameters(a: string, ...rests: string[]) { ->nonExportedFooWithRestParameters : Symbol(nonExportedFooWithRestParameters, Decl(declFileFunctions_0.ts, 33, 1)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 34, 42)) ->rests : Symbol(rests, Decl(declFileFunctions_0.ts, 34, 52)) +>nonExportedFooWithRestParameters : Symbol(nonExportedFooWithRestParameters, Decl(declFileFunctions_0.ts, 37, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 38, 42)) +>rests : Symbol(rests, Decl(declFileFunctions_0.ts, 38, 52)) return a + rests.join(""); ->a : Symbol(a, Decl(declFileFunctions_0.ts, 34, 42)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 38, 42)) >rests.join : Symbol(Array.join, Decl(lib.d.ts, 1035, 31)) ->rests : Symbol(rests, Decl(declFileFunctions_0.ts, 34, 52)) +>rests : Symbol(rests, Decl(declFileFunctions_0.ts, 38, 52)) >join : Symbol(Array.join, Decl(lib.d.ts, 1035, 31)) } function nonExportedFooWithOverloads(a: string): string; ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 36, 1), Decl(declFileFunctions_0.ts, 38, 56), Decl(declFileFunctions_0.ts, 39, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 38, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 42, 37)) function nonExportedFooWithOverloads(a: number): number; ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 36, 1), Decl(declFileFunctions_0.ts, 38, 56), Decl(declFileFunctions_0.ts, 39, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 39, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 43, 37)) function nonExportedFooWithOverloads(a: any): any { ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 36, 1), Decl(declFileFunctions_0.ts, 38, 56), Decl(declFileFunctions_0.ts, 39, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 40, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 44, 37)) return a; ->a : Symbol(a, Decl(declFileFunctions_0.ts, 40, 37)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 44, 37)) } === tests/cases/compiler/declFileFunctions_1.ts === diff --git a/tests/baselines/reference/declFileFunctions.types b/tests/baselines/reference/declFileFunctions.types index b9e94f7ffcd..e6ecc53b043 100644 --- a/tests/baselines/reference/declFileFunctions.types +++ b/tests/baselines/reference/declFileFunctions.types @@ -60,6 +60,15 @@ export function fooWithSingleOverload(a: any) { >a : any } +export function fooWithTypePredicate(a: any): a is number { +>fooWithTypePredicate : (a: any) => boolean +>a : any +>a : any + + return true; +>true : boolean +} + /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { >nonExportedFoo : () => void From 28976a0e344258605e777d4d75217084bcb9dc0d Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 9 Jul 2015 11:13:32 +0800 Subject: [PATCH 21/29] Adds type predicate signature display and addresses CR feedback --- src/compiler/checker.ts | 340 +++++++++--------- src/compiler/declarationEmitter.ts | 2 +- tests/cases/compiler/declFileFunctions.ts | 9 + .../signatureHelpOnTypePredicates.ts | 20 ++ 4 files changed, 206 insertions(+), 165 deletions(-) create mode 100644 tests/cases/fourslash/signatureHelpOnTypePredicates.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b34952f3ae..03a3f7efa9b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25,12 +25,12 @@ namespace ts { // Cancellation that controls whether or not we can cancel in the middle of type checking. // In general cancelling is *not* safe for the type checker. We might be in the middle of // computing something, and we will leave our internals in an inconsistent state. Callers - // who set the cancellation token should catch if a cancellation exception occurs, and + // who set the cancellation token should catch if a cancellation exception occurs, and // should throw away and create a new TypeChecker. // // Currently we only support setting the cancellation token when getting diagnostics. This // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if - // they no longer need the information (for example, if the user started editing again). + // they no longer need the information (for example, if the user started editing again). let cancellationToken: CancellationToken; let Symbol = objectAllocator.getSymbolConstructor(); @@ -117,7 +117,7 @@ namespace ts { let globals: SymbolTable = {}; let globalESSymbolConstructorSymbol: Symbol; - + let getGlobalPromiseConstructorSymbol: () => Symbol; let globalObjectType: ObjectType; @@ -148,7 +148,7 @@ namespace ts { let getInstantiatedGlobalPromiseLikeType: () => ObjectType; let getGlobalPromiseConstructorLikeType: () => ObjectType; let getGlobalThenableType: () => ObjectType; - + let tupleTypes: Map = {}; let unionTypes: Map = {}; let intersectionTypes: Map = {}; @@ -158,7 +158,7 @@ namespace ts { let emitParam = false; let emitAwaiter = false; let emitGenerator = false; - + let resolutionTargets: Object[] = []; let resolutionResults: boolean[] = []; @@ -406,7 +406,7 @@ namespace ts { let moduleExports = getSymbolOfNode(location).exports; if (location.kind === SyntaxKind.SourceFile || (location.kind === SyntaxKind.ModuleDeclaration && (location).name.kind === SyntaxKind.StringLiteral)) { - + // It's an external module. Because of module/namespace merging, a module's exports are in scope, // yet we never want to treat an export specifier as putting a member in scope. Therefore, // if the name we find is purely an export specifier, it is not actually considered in scope. @@ -526,7 +526,7 @@ namespace ts { } break; case SyntaxKind.Decorator: - // Decorators are resolved at the class declaration. Resolving at the parameter + // Decorators are resolved at the class declaration. Resolving at the parameter // or member would result in looking up locals in the method. // // function y() {} @@ -1948,7 +1948,19 @@ namespace ts { writePunctuation(writer, SyntaxKind.ColonToken); } writeSpace(writer); - buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, symbolStack); + + let returnType: Type; + if (signature.typePredicate) { + writer.writeParameter(signature.typePredicate.parameterName); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.IsKeyword); + writeSpace(writer); + returnType = signature.typePredicate.type; + } + else { + returnType = getReturnTypeOfSignature(signature); + } + buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack); } function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { @@ -2098,7 +2110,7 @@ namespace ts { case SyntaxKind.ParenthesizedType: return isDeclarationVisible(node.parent); - // Default binding, import specifier and namespace import is visible + // Default binding, import specifier and namespace import is visible // only on demand so by default it is not visible case SyntaxKind.ImportClause: case SyntaxKind.NamespaceImport: @@ -3864,7 +3876,7 @@ namespace ts { function getGlobalType(name: string, arity = 0): ObjectType { return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), arity); } - + function tryGetGlobalType(name: string, arity = 0): ObjectType { return getTypeOfGlobalSymbol(getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined), arity); } @@ -3892,7 +3904,7 @@ namespace ts { ? createTypeReference(globalTypedPropertyDescriptorType, [propertyType]) : emptyObjectType; } - + /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ @@ -4117,7 +4129,7 @@ namespace ts { } return links.resolvedType; } - + function getTypeFromTypeNode(node: TypeNode): Type { switch (node.kind) { case SyntaxKind.AnyKeyword: @@ -6053,7 +6065,7 @@ namespace ts { error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); } } - + if (node.parserContextFlags & ParserContextFlags.Await) { getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments; getNodeLinks(node).flags |= NodeCheckFlags.LexicalArguments; @@ -6746,7 +6758,7 @@ namespace ts { // c is represented in the tree as a spread element in an array literal. // But c really functions as a rest element, and its purpose is to provide // a contextual type for the right hand side of the assignment. Therefore, - // instead of calling checkExpression on "...c", which will give an error + // instead of calling checkExpression on "...c", which will give an error // if c is not iterable/array-like, we need to act as if we are trying to // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error @@ -7399,7 +7411,7 @@ namespace ts { if (flags & NodeFlags.Abstract) { // A method cannot be accessed in a super property access if the method is abstract. - // This error could mask a private property access error. But, a member + // This error could mask a private property access error. But, a member // cannot simultaneously be private and abstract, so this will trigger an // additional error elsewhere. @@ -7478,7 +7490,7 @@ namespace ts { } return unknownType; } - + getNodeLinks(node).resolvedSymbol = prop; if (prop.parent && prop.parent.flags & SymbolFlags.Class) { @@ -7875,7 +7887,7 @@ namespace ts { let paramType = getTypeAtPosition(signature, i); let argType = getEffectiveArgumentType(node, i, arg); - // If the effective argument type is 'undefined', there is no synthetic type + // If the effective argument type is 'undefined', there is no synthetic type // for the argument. In that case, we should check the argument. if (argType === undefined) { // For context sensitive arguments we pass the identityMapper, which is a signal to treat all @@ -7947,8 +7959,8 @@ namespace ts { // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter) let paramType = getTypeAtPosition(signature, i); let argType = getEffectiveArgumentType(node, i, arg); - - // If the effective argument type is 'undefined', there is no synthetic type + + // If the effective argument type is 'undefined', there is no synthetic type // for the argument. In that case, we should check the argument. if (argType === undefined) { argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors @@ -8001,18 +8013,18 @@ namespace ts { return args; } - + /** * Returns the effective argument count for a node that works like a function invocation. * If 'node' is a Decorator, the number of arguments is derived from the decoration * target and the signature: - * If 'node.target' is a class declaration or class expression, the effective argument + * If 'node.target' is a class declaration or class expression, the effective argument * count is 1. * If 'node.target' is a parameter declaration, the effective argument count is 3. * If 'node.target' is a property declaration, the effective argument count is 2. - * If 'node.target' is a method or accessor declaration, the effective argument count + * If 'node.target' is a method or accessor declaration, the effective argument count * is 3, although it can be 2 if the signature only accepts two arguments, allowing - * us to match a property decorator. + * us to match a property decorator. * Otherwise, the argument count is the length of the 'args' array. */ function getEffectiveArgumentCount(node: CallLikeExpression, args: Expression[], signature: Signature) { @@ -8024,7 +8036,7 @@ namespace ts { return 1; case SyntaxKind.PropertyDeclaration: - // A property declaration decorator will have two arguments (see + // A property declaration decorator will have two arguments (see // `PropertyDecorator` in core.d.ts) return 2; @@ -8033,12 +8045,12 @@ namespace ts { case SyntaxKind.SetAccessor: // A method or accessor declaration decorator will have two or three arguments (see // `PropertyDecorator` and `MethodDecorator` in core.d.ts) - // If the method decorator signature only accepts a target and a key, we will only + // If the method decorator signature only accepts a target and a key, we will only // type check those arguments. return signature.parameters.length >= 3 ? 3 : 2; case SyntaxKind.Parameter: - // A parameter declaration decorator will have three arguments (see + // A parameter declaration decorator will have three arguments (see // `ParameterDecorator` in core.d.ts) return 3; @@ -8048,47 +8060,47 @@ namespace ts { return args.length; } } - + /** * Returns the effective type of the first argument to a decorator. * If 'node' is a class declaration or class expression, the effective argument type * is the type of the static side of the class. * If 'node' is a parameter declaration, the effective argument type is either the type - * of the static or instance side of the class for the parameter's parent method, + * of the static or instance side of the class for the parameter's parent method, * depending on whether the method is declared static. * For a constructor, the type is always the type of the static side of the class. - * If 'node' is a property, method, or accessor declaration, the effective argument - * type is the type of the static or instance side of the parent class for class - * element, depending on whether the element is declared static. + * If 'node' is a property, method, or accessor declaration, the effective argument + * type is the type of the static or instance side of the parent class for class + * element, depending on whether the element is declared static. */ function getEffectiveDecoratorFirstArgumentType(node: Node): Type { // The first argument to a decorator is its `target`. switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - // For a class decorator, the `target` is the type of the class (e.g. the + // For a class decorator, the `target` is the type of the class (e.g. the // "static" or "constructor" side of the class) let classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); case SyntaxKind.Parameter: - // For a parameter decorator, the `target` is the parent type of the - // parameter's containing method. + // For a parameter decorator, the `target` is the parent type of the + // parameter's containing method. node = node.parent; if (node.kind === SyntaxKind.Constructor) { let classSymbol = getSymbolOfNode(node); return getTypeOfSymbol(classSymbol); } - + // fall-through - + case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: // For a property or method decorator, the `target` is the // "static"-side type of the parent of the member if the member is - // declared "static"; otherwise, it is the "instance"-side type of the + // declared "static"; otherwise, it is the "instance"-side type of the // parent of the member. return getParentTypeOfClassElement(node); @@ -8097,19 +8109,19 @@ namespace ts { return unknownType; } } - + /** * Returns the effective type for the second argument to a decorator. * If 'node' is a parameter, its effective argument type is one of the following: - * If 'node.parent' is a constructor, the effective argument type is 'any', as we + * If 'node.parent' is a constructor, the effective argument type is 'any', as we * will emit `undefined`. - * If 'node.parent' is a member with an identifier, numeric, or string literal name, + * If 'node.parent' is a member with an identifier, numeric, or string literal name, * the effective argument type will be a string literal type for the member name. - * If 'node.parent' is a computed property name, the effective argument type will + * If 'node.parent' is a computed property name, the effective argument type will * either be a symbol type or the string type. - * If 'node' is a member with an identifier, numeric, or string literal name, the + * If 'node' is a member with an identifier, numeric, or string literal name, the * effective argument type will be a string literal type for the member name. - * If 'node' is a computed property name, the effective argument type will either + * If 'node' is a computed property name, the effective argument type will either * be a symbol type or the string type. * A class decorator does not have a second argument type. */ @@ -8126,18 +8138,18 @@ namespace ts { // For a constructor parameter decorator, the `propertyKey` will be `undefined`. return anyType; } - + // For a non-constructor parameter decorator, the `propertyKey` will be either // a string or a symbol, based on the name of the parameter's containing method. - + // fall-through - + case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: // The `propertyKey` for a property or method decorator will be a - // string literal type if the member name is an identifier, number, or string; + // string literal type if the member name is an identifier, number, or string; // otherwise, if the member name is a computed property name it will // be either string or symbol. let element = node; @@ -8167,11 +8179,11 @@ namespace ts { return unknownType; } } - + /** * Returns the effective argument type for the third argument to a decorator. * If 'node' is a parameter, the effective argument type is the number type. - * If 'node' is a method or accessor, the effective argument type is a + * If 'node' is a method or accessor, the effective argument type is a * `TypedPropertyDescriptor` instantiated with the type of the member. * Class and property decorators do not have a third effective argument. */ @@ -8204,7 +8216,7 @@ namespace ts { return unknownType; } } - + /** * Returns the effective argument type for the provided argument to a decorator. */ @@ -8222,12 +8234,12 @@ namespace ts { Debug.fail("Decorators should not have a fourth synthetic argument."); return unknownType; } - + /** * Gets the effective argument type for an argument in a call expression. */ function getEffectiveArgumentType(node: CallLikeExpression, argIndex: number, arg: Expression): Type { - // Decorators provide special arguments, a tagged template expression provides + // Decorators provide special arguments, a tagged template expression provides // a special first argument, and string literals get string literal types // unless we're reporting errors if (node.kind === SyntaxKind.Decorator) { @@ -8238,12 +8250,12 @@ namespace ts { } // This is not a synthetic argument, so we return 'undefined' - // to signal that the caller needs to check the argument. + // to signal that the caller needs to check the argument. return undefined; } - + /** - * Gets the effective argument expression for an argument in a call expression. + * Gets the effective argument expression for an argument in a call expression. */ function getEffectiveArgument(node: CallLikeExpression, args: Expression[], argIndex: number) { // For a decorator or the first argument of a tagged template expression we return undefined. @@ -8309,7 +8321,7 @@ namespace ts { // For a tagged template, then the first argument be 'undefined' if necessary // because it represents a TemplateStringsArray. // - // For a decorator, no arguments are susceptible to contextual typing due to the fact + // For a decorator, no arguments are susceptible to contextual typing due to the fact // decorators are applied to a declaration by the emitter, and not to an expression. let excludeArgument: boolean[]; if (!isDecorator) { @@ -8651,7 +8663,7 @@ namespace ts { return resolveCall(node, callSignatures, candidatesOutArray); } - + /** * Gets the localized diagnostic head message to use for errors when resolving a decorator as a call expression. */ @@ -8797,7 +8809,7 @@ namespace ts { links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper); } } - + function createPromiseType(promisedType: Type): Type { // creates a `Promise` type where `T` is the promisedType argument let globalPromiseType = getGlobalPromiseType(); @@ -8806,7 +8818,7 @@ namespace ts { promisedType = getAwaitedType(promisedType); return createTypeReference(globalPromiseType, [promisedType]); } - + return emptyObjectType; } @@ -8815,15 +8827,15 @@ namespace ts { if (!func.body) { return unknownType; } - + let isAsync = isAsyncFunctionLike(func); let type: Type; if (func.body.kind !== SyntaxKind.Block) { - type = checkExpressionCached(func.body, contextualMapper); + type = checkExpressionCached(func.body, contextualMapper); if (isAsync) { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so the - // return type of the body should be unwrapped to its awaited type, which we will wrap in + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so the + // return type of the body should be unwrapped to its awaited type, which we will wrap in // the native Promise type later in this function. type = checkAwaitedType(type, func, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); } @@ -8852,13 +8864,13 @@ namespace ts { error(func, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type); return unknownType; } - + return promiseType; } else { return voidType; } - } + } } // When yield/return statements are contextually typed we allow the return type to be a union type. // Otherwise we require the yield/return expressions to have a best common supertype. @@ -8881,19 +8893,19 @@ namespace ts { if (!contextualSignature) { reportErrorsFromWidening(func, type); } - + let widenedType = getWidenedType(type); if (isAsync) { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so the + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body is awaited type of the body, wrapped in a native Promise type. let promiseType = createPromiseType(widenedType); if (promiseType === emptyObjectType) { error(func, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type); return unknownType; } - - return promiseType; + + return promiseType; } else { return widenedType; @@ -8928,13 +8940,13 @@ namespace ts { forEachReturnStatement(body, returnStatement => { let expr = returnStatement.expression; if (expr) { - let type = checkExpressionCached(expr, contextualMapper); + let type = checkExpressionCached(expr, contextualMapper); if (isAsync) { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so the - // return type of the body should be unwrapped to its awaited type, which should be wrapped in + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so the + // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - type = checkAwaitedType(type, body.parent, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); + type = checkAwaitedType(type, body.parent, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); } if (!contains(aggregatedTypes, type)) { @@ -9006,12 +9018,12 @@ namespace ts { if (contextualMapper === identityMapper && isContextSensitive(node)) { return anyFunctionType; } - + let isAsync = isAsyncFunctionLike(node); if (isAsync) { emitAwaiter = true; } - + let links = getNodeLinks(node); let type = getTypeOfSymbol(node.symbol); // Check if function expression is contextually typed and assign parameter types if so @@ -9048,7 +9060,7 @@ namespace ts { function checkFunctionExpressionOrObjectLiteralMethodBody(node: FunctionExpression | MethodDeclaration) { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); - + let isAsync = isAsyncFunctionLike(node); if (isAsync) { emitAwaiter = true; @@ -9059,7 +9071,7 @@ namespace ts { if (returnType && isAsync) { promisedType = checkAsyncFunctionReturnType(node); } - + if (returnType && !node.asteriskToken) { checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, isAsync ? promisedType : returnType); } @@ -9078,10 +9090,10 @@ namespace ts { checkSourceElement(node.body); } else { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so we - // should not be checking assignability of a promise to the return type. Instead, we need to - // check assignability of the awaited type of the expression body against the promised type of + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so we + // should not be checking assignability of a promise to the return type. Instead, we need to + // check assignability of the awaited type of the expression body against the promised type of // its return type annotation. let exprType = checkExpression(node.body); if (returnType) { @@ -9093,7 +9105,7 @@ namespace ts { checkTypeAssignableTo(exprType, returnType, node.body); } } - + checkFunctionAndClassExpressionBodies(node.body); } } @@ -9215,7 +9227,7 @@ namespace ts { let operandType = checkExpression(node.expression); return checkAwaitedType(operandType, node); } - + function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type { let operandType = checkExpression(node.operand); switch (node.operator) { @@ -9688,7 +9700,7 @@ namespace ts { node.contextualType = saveContextualType; return result; } - + function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type { let links = getNodeLinks(node); if (!links.resolvedType) { @@ -9895,7 +9907,7 @@ namespace ts { if (node.questionToken && isBindingPattern(node.name) && func.body) { error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); } - + // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. if (node.dotDotDotToken && !isBindingPattern(node.name) && !isArrayType(getTypeOfSymbol(node.symbol))) { @@ -10113,7 +10125,7 @@ namespace ts { // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration checkFunctionLikeDeclaration(node); - + // Abstract methods cannot have an implementation. // Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node. if(node.flags & NodeFlags.Abstract && node.body) { @@ -10548,7 +10560,7 @@ namespace ts { } // Abstract methods can't have an implementation -- in particular, they don't need one. - if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && + if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) ) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } @@ -10666,13 +10678,13 @@ namespace ts { if (!message) { message = Diagnostics.Operand_for_await_does_not_have_a_valid_callable_then_member; } - + error(location, message); } - + return unknownType; } - + return type; } @@ -10690,16 +10702,16 @@ namespace ts { // ) => any // ): any; // } - // - + // + if (promise.flags & TypeFlags.Any) { return undefined; } - + if ((promise.flags & TypeFlags.Reference) && (promise).target === tryGetGlobalPromiseType()) { return (promise).typeArguments[0]; } - + let globalPromiseLikeType = getInstantiatedGlobalPromiseLikeType(); if (globalPromiseLikeType === emptyObjectType || !isTypeAssignableTo(promise, globalPromiseLikeType)) { return undefined; @@ -10709,58 +10721,58 @@ namespace ts { if (thenFunction && (thenFunction.flags & TypeFlags.Any)) { return undefined; } - + let thenSignatures = thenFunction ? getSignaturesOfType(thenFunction, SignatureKind.Call) : emptyArray; if (thenSignatures.length === 0) { return undefined; } - + let onfulfilledParameterType = getUnionType(map(thenSignatures, getTypeOfFirstParameterOfSignature)); if (onfulfilledParameterType.flags & TypeFlags.Any) { return undefined; } - + let onfulfilledParameterSignatures = getSignaturesOfType(onfulfilledParameterType, SignatureKind.Call); if (onfulfilledParameterSignatures.length === 0) { return undefined; } - + let valueParameterType = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature)); return valueParameterType; } - + function getTypeOfFirstParameterOfSignature(signature: Signature) { return getTypeAtPosition(signature, 0); } - + /** * Gets the "awaited type" of a type. * @param type The type to await. - * @remarks The "awaited type" of an expression is its "promised type" if the expression is a + * @remarks The "awaited type" of an expression is its "promised type" if the expression is a * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ function getAwaitedType(type: Type) { return checkAwaitedType(type, /*location*/ undefined, /*message*/ undefined); } - + function checkAwaitedType(type: Type, location?: Node, message?: DiagnosticMessage) { return checkAwaitedTypeWorker(type); - + function checkAwaitedTypeWorker(type: Type): Type { if (type.flags & TypeFlags.Union) { let types: Type[] = []; for (let constituentType of (type).types) { types.push(checkAwaitedTypeWorker(constituentType)); } - + return getUnionType(types); } else { let promisedType = getPromisedType(type); if (promisedType === undefined) { // The type was not a PromiseLike, so it could not be unwrapped any further. - // As long as the type does not have a callable "then" property, it is + // As long as the type does not have a callable "then" property, it is // safe to return the type; otherwise, an error will have been reported in // the call to checkNonThenableType and we will return unknownType. // @@ -10771,7 +10783,7 @@ namespace ts { // The "thenable" does not match the minimal definition for a PromiseLike. When // a Promise/A+-compatible or ES6 promise tries to adopt this value, the promise // will never settle. We treat this as an error to help flag an early indicator - // of a runtime problem. If the user wants to return this value from an async + // of a runtime problem. If the user wants to return this value from an async // function, they would need to wrap it in some other value. If they want it to // be treated as a promise, they can cast to . return checkNonThenableType(type, location, message); @@ -10779,70 +10791,70 @@ namespace ts { else { if (type.id === promisedType.id || awaitedTypeStack.indexOf(promisedType.id) >= 0) { // We have a bad actor in the form of a promise whose promised type is - // the same promise type, or a mutually recursive promise. Return the - // unknown type as we cannot guess the shape. If this were the actual + // the same promise type, or a mutually recursive promise. Return the + // unknown type as we cannot guess the shape. If this were the actual // case in the JavaScript, this Promise would never resolve. // - // An example of a bad actor with a singly-recursive promise type might + // An example of a bad actor with a singly-recursive promise type might // be: // // interface BadPromise { // then( - // onfulfilled: (value: BadPromise) => any, + // onfulfilled: (value: BadPromise) => any, // onrejected: (error: any) => any): BadPromise; // } // - // The above interface will pass the PromiseLike check, and return a - // promised type of `BadPromise`. Since this is a self reference, we + // The above interface will pass the PromiseLike check, and return a + // promised type of `BadPromise`. Since this is a self reference, we // don't want to keep recursing ad infinitum. // - // An example of a bad actor in the form of a mutually-recursive + // An example of a bad actor in the form of a mutually-recursive // promise type might be: // // interface BadPromiseA { // then( - // onfulfilled: (value: BadPromiseB) => any, + // onfulfilled: (value: BadPromiseB) => any, // onrejected: (error: any) => any): BadPromiseB; // } // // interface BadPromiseB { // then( - // onfulfilled: (value: BadPromiseA) => any, + // onfulfilled: (value: BadPromiseA) => any, // onrejected: (error: any) => any): BadPromiseA; // } // if (location) { error( - location, - Diagnostics._0_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, + location, + Diagnostics._0_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, symbolToString(type.symbol)); } - + return unknownType; } - + // Keep track of the type we're about to unwrap to avoid bad recursive promise types. // See the comments above for more information. awaitedTypeStack.push(type.id); let awaitedType = checkAwaitedTypeWorker(promisedType); awaitedTypeStack.pop(); - return awaitedType; + return awaitedType; } } } } /** - * Checks the return type of an async function to ensure it is a compatible + * Checks the return type of an async function to ensure it is a compatible * Promise implementation. * @param node The signature to check * @param returnType The return type for the function - * @remarks - * This checks that an async function has a valid Promise-compatible return type, - * and returns the *awaited type* of the promise. An async function has a valid - * Promise-compatible return type if the resolved value of the return type has a + * @remarks + * This checks that an async function has a valid Promise-compatible return type, + * and returns the *awaited type* of the promise. An async function has a valid + * Promise-compatible return type if the resolved value of the return type has a * construct signature that takes in an `initializer` function that in turn supplies - * a `resolve` function as one of its arguments and results in an object with a + * a `resolve` function as one of its arguments and results in an object with a * callable `then` signature. */ function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type { @@ -10855,7 +10867,7 @@ namespace ts { // As part of our emit for an async function, we will need to emit the entity name of // the return type annotation as an expression. To meet the necessary runtime semantics - // for __awaiter, we must also check that the type of the declaration (e.g. the static + // for __awaiter, we must also check that the type of the declaration (e.g. the static // side or "constructor" of the promise type) is compatible `PromiseConstructorLike`. // // An example might be (from lib.es6.d.ts): @@ -10863,11 +10875,11 @@ namespace ts { // interface Promise { ... } // interface PromiseConstructor { // new (...): Promise; - // } + // } // declare var Promise: PromiseConstructor; // - // When an async function declares a return type annotation of `Promise`, we - // need to get the type of the `Promise` variable declaration above, which would + // When an async function declares a return type annotation of `Promise`, we + // need to get the type of the `Promise` variable declaration above, which would // be `PromiseConstructor`. // // The same case applies to a class: @@ -10879,20 +10891,20 @@ namespace ts { // // When we get the type of the `Promise` symbol here, we get the type of the static // side of the `Promise` class, which would be `{ new (...): Promise }`. - + let promiseType = getTypeFromTypeNode(node.type); if (promiseType === unknownType && compilerOptions.isolatedModules) { - // If we are compiling with isolatedModules, we may not be able to resolve the + // If we are compiling with isolatedModules, we may not be able to resolve the // type as a value. As such, we will just return unknownType; return unknownType; } - + let promiseConstructor = getMergedSymbol(promiseType.symbol); if (!promiseConstructor || !symbolIsValue(promiseConstructor)) { error(node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeToString(promiseType)); return unknownType } - + // Validate the promise constructor type. let promiseConstructorType = getTypeOfSymbol(promiseConstructor); if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) { @@ -10913,7 +10925,7 @@ namespace ts { // Get and return the awaited type of the return type. return checkAwaitedType(promiseType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type); } - + /** Check a decorator */ function checkDecorator(node: Decorator): void { let signature = getResolvedSignature(node); @@ -10963,11 +10975,11 @@ namespace ts { headMessage, errorInfo); } - + /** Checks a type reference node as an expression. */ function checkTypeNodeAsExpression(node: TypeNode) { // When we are emitting type metadata for decorators, we need to try to check the type - // as if it were an expression so that we can emit the type in a value position when we + // as if it were an expression so that we can emit the type in a value position when we // serialize the type metadata. if (node && node.kind === SyntaxKind.TypeReference) { let type = getTypeFromTypeNode(node); @@ -10982,7 +10994,7 @@ namespace ts { } /** - * Checks the type annotation of an accessor declaration or property declaration as + * Checks the type annotation of an accessor declaration or property declaration as * an expression if it is a type reference to a type with a value declaration. */ function checkTypeAnnotationAsExpression(node: AccessorDeclaration | PropertyDeclaration | ParameterDeclaration | MethodDeclaration) { @@ -11004,7 +11016,7 @@ namespace ts { break; } } - + /** Checks the type annotation of the parameters of a function/method or the constructor of a class as expressions */ function checkParameterTypeAnnotationsAsExpressions(node: FunctionLikeDeclaration) { // ensure all type annotations with a value declaration are checked as an expression @@ -11078,9 +11090,9 @@ namespace ts { if (!compilerOptions.experimentalAsyncFunctions) { error(node, Diagnostics.Experimental_support_for_async_functions_is_a_feature_that_is_subject_to_change_in_a_future_release_Specify_experimentalAsyncFunctions_to_remove_this_warning); } - + emitAwaiter = true; - } + } // Do not use hasDynamicName here, because that returns false for well known symbols. // We want to perform checkComputedPropertyName for all computed properties, including @@ -11120,7 +11132,7 @@ namespace ts { if (isAsync) { promisedType = checkAsyncFunctionReturnType(node); } - + checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, isAsync ? promisedType : returnType); } @@ -11332,7 +11344,7 @@ namespace ts { } } } - + // Check that a parameter initializer contains no references to parameters declared to the right of itself function checkParameterInitializer(node: VariableLikeDeclaration): void { if (getRootDeclaration(node).kind !== SyntaxKind.Parameter) { @@ -11653,7 +11665,7 @@ namespace ts { return elementType || anyType; } - + /** * We want to treat type as an iterable, and get the type it is an iterable of. The iterable * must have the following structure (annotated with the names of the variables below): @@ -12280,20 +12292,20 @@ namespace ts { // In order to resolve whether the inherited method was overriden in the base class or not, // we compare the Symbols obtained. Since getTargetSymbol returns the symbol on the *uninstantiated* // type declaration, derived and base resolve to the same symbol even in the case of generic classes. - if (derived === base) { + if (derived === base) { // derived class inherits base without override/redeclaration let derivedClassDecl = getDeclarationOfKind(type.symbol, SyntaxKind.ClassDeclaration); // It is an error to inherit an abstract member without implementing it or being declared abstract. - // If there is no declaration for the derived class (as in the case of class expressions), - // then the class cannot be declared abstract. + // If there is no declaration for the derived class (as in the case of class expressions), + // then the class cannot be declared abstract. if ( baseDeclarationFlags & NodeFlags.Abstract && (!derivedClassDecl || !(derivedClassDecl.flags & NodeFlags.Abstract))) { error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, typeToString(type), symbolToString(baseProperty), typeToString(baseType)); } } - else { + else { // derived overrides base. let derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived); if ((baseDeclarationFlags & NodeFlags.Private) || (derivedDeclarationFlags & NodeFlags.Private)) { @@ -12764,7 +12776,7 @@ namespace ts { } } - // if the module merges with a class declaration in the same lexical scope, + // if the module merges with a class declaration in the same lexical scope, // we need to track this to ensure the correct emit. let mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); if (mergedClass && @@ -13298,7 +13310,7 @@ namespace ts { forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope); potentialThisCollisions.length = 0; } - + if (emitExtends) { links.flags |= NodeCheckFlags.EmitExtends; } @@ -13310,11 +13322,11 @@ namespace ts { if (emitParam) { links.flags |= NodeCheckFlags.EmitParam; } - + if (emitAwaiter) { links.flags |= NodeCheckFlags.EmitAwaiter; } - + if (emitGenerator || (emitAwaiter && languageVersion < ScriptTarget.ES6)) { links.flags |= NodeCheckFlags.EmitGenerator; } @@ -13713,7 +13725,7 @@ namespace ts { } /** - * Gets either the static or instance type of a class element, based on + * Gets either the static or instance type of a class element, based on * whether the element is declared as "static". */ function getParentTypeOfClassElement(node: ClassElement) { @@ -13722,7 +13734,7 @@ namespace ts { ? getTypeOfSymbol(classSymbol) : getDeclaredTypeOfSymbol(classSymbol); } - + // Return the list of properties of the given type, augmented with properties from Function // if the type has call or construct signatures function getAugmentedPropertiesOfType(type: Type): Symbol[] { @@ -14061,7 +14073,7 @@ namespace ts { // * The serialized type of an AccessorDeclaration is the serialized type of the return type annotation of its getter or parameter type annotation of its setter. // * The serialized type of any other FunctionLikeDeclaration is "Function". // * The serialized type of any other node is "void 0". - // + // // For rules on serializing type annotations, see `serializeTypeNode`. switch (node.kind) { case SyntaxKind.ClassDeclaration: return "Function"; @@ -14075,14 +14087,14 @@ namespace ts { } return "void 0"; } - + /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */ function serializeParameterTypesOfNode(node: Node): (string | string[])[] { // serialization of parameter types uses the following rules: // // * If the declaration is a class, the parameters of the first constructor with a body are used. // * If the declaration is function-like and has a body, the parameters of the function are used. - // + // // For the rules on serializing the type of each parameter declaration, see `serializeTypeOfDeclaration`. if (node) { var valueDeclaration: FunctionLikeDeclaration; @@ -14299,21 +14311,21 @@ namespace ts { anyArrayType = createArrayType(anyType); } - + function createInstantiatedPromiseLikeType(): ObjectType { let promiseLikeType = getGlobalPromiseLikeType(); if (promiseLikeType !== emptyObjectType) { return createTypeReference(promiseLikeType, [anyType]); } - + return emptyObjectType; } - + function createThenableType() { // build the thenable type that is used to verify against a non-promise "thenable" operand to `await`. let thenPropertySymbol = createSymbol(SymbolFlags.Transient | SymbolFlags.Property, "then"); getSymbolLinks(thenPropertySymbol).type = globalFunctionType; - + let thenableType = createObjectType(TypeFlags.Anonymous); thenableType.properties = [thenPropertySymbol]; thenableType.members = createSymbolTable(thenableType.properties); diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 3db032b8d0d..97c85c70de1 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -401,7 +401,7 @@ namespace ts { } function emitTypePredicate(type: TypePredicateNode) { - writeEntityName(type.parameterName); + writeTextOfNode(currentSourceFile, type.parameterName); write(" is "); emitType(type.type); } diff --git a/tests/cases/compiler/declFileFunctions.ts b/tests/cases/compiler/declFileFunctions.ts index 36972d427f0..7b9c55e9214 100644 --- a/tests/cases/compiler/declFileFunctions.ts +++ b/tests/cases/compiler/declFileFunctions.ts @@ -31,6 +31,15 @@ export function fooWithSingleOverload(a: any) { export function fooWithTypePredicate(a: any): a is number { return true; } +export function fooWithTypePredicateAndMulitpleParams(a: any, b: any, c: any): a is number { + return true; +} +export function fooWithTypeTypePredicateAndGeneric(a: any): a is T { + return true; +} +export function fooWithTypeTypePredicateAndRestParam(a: any, ...rest): a is number { + return true; +} /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { diff --git a/tests/cases/fourslash/signatureHelpOnTypePredicates.ts b/tests/cases/fourslash/signatureHelpOnTypePredicates.ts new file mode 100644 index 00000000000..bfaa7df2502 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnTypePredicates.ts @@ -0,0 +1,20 @@ +/// + +//// function f1(a: any): a is number {} +//// function f2(a: any): a is T {} +//// function f3(a: any, ...b): a is number {} +//// f1(/*1*/) +//// f2(/*2*/) +//// f3(/*3*/) + +goTo.marker("1"); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("f1(a: any): a is number"); + +goTo.marker("2"); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("f2(a: any): a is T"); + +goTo.marker("3"); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("f3(a: any, ...b: any[]): a is number"); \ No newline at end of file From 52b1496a64d0e2ece12834668b295e519b2d9e25 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Thu, 9 Jul 2015 11:48:42 +0800 Subject: [PATCH 22/29] Accepts baselines --- .../baselines/reference/declFileFunctions.js | 28 +++++++++ .../reference/declFileFunctions.symbols | 62 +++++++++++++------ .../reference/declFileFunctions.types | 31 +++++++++- tests/baselines/reference/isArray.types | 4 +- .../reference/typeGuardFunction.types | 46 +++++++------- .../typeGuardFunctionErrors.errors.txt | 16 ++--- .../reference/typeGuardFunctionGenerics.types | 34 +++++----- .../reference/typeGuardOfFormIsType.types | 22 +++---- .../typeGuardOfFormIsTypeOnInterfaces.types | 22 +++---- 9 files changed, 174 insertions(+), 91 deletions(-) diff --git a/tests/baselines/reference/declFileFunctions.js b/tests/baselines/reference/declFileFunctions.js index d3debf4d50c..163fa1905c8 100644 --- a/tests/baselines/reference/declFileFunctions.js +++ b/tests/baselines/reference/declFileFunctions.js @@ -29,6 +29,15 @@ export function fooWithSingleOverload(a: any) { export function fooWithTypePredicate(a: any): a is number { return true; } +export function fooWithTypePredicateAndMulitpleParams(a: any, b: any, c: any): a is number { + return true; +} +export function fooWithTypeTypePredicateAndGeneric(a: any): a is T { + return true; +} +export function fooWithTypeTypePredicateAndRestParam(a: any, ...rest): a is number { + return true; +} /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { @@ -100,6 +109,22 @@ function fooWithTypePredicate(a) { return true; } exports.fooWithTypePredicate = fooWithTypePredicate; +function fooWithTypePredicateAndMulitpleParams(a, b, c) { + return true; +} +exports.fooWithTypePredicateAndMulitpleParams = fooWithTypePredicateAndMulitpleParams; +function fooWithTypeTypePredicateAndGeneric(a) { + return true; +} +exports.fooWithTypeTypePredicateAndGeneric = fooWithTypeTypePredicateAndGeneric; +function fooWithTypeTypePredicateAndRestParam(a) { + var rest = []; + for (var _i = 1; _i < arguments.length; _i++) { + rest[_i - 1] = arguments[_i]; + } + return true; +} +exports.fooWithTypeTypePredicateAndRestParam = fooWithTypeTypePredicateAndRestParam; /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { } @@ -153,6 +178,9 @@ export declare function fooWithOverloads(a: string): string; export declare function fooWithOverloads(a: number): number; export declare function fooWithSingleOverload(a: string): string; export declare function fooWithTypePredicate(a: any): a is number; +export declare function fooWithTypePredicateAndMulitpleParams(a: any, b: any, c: any): a is number; +export declare function fooWithTypeTypePredicateAndGeneric(a: any): a is T; +export declare function fooWithTypeTypePredicateAndRestParam(a: any, ...rest: any[]): a is number; //// [declFileFunctions_1.d.ts] /** This comment should appear for foo*/ declare function globalfoo(): void; diff --git a/tests/baselines/reference/declFileFunctions.symbols b/tests/baselines/reference/declFileFunctions.symbols index 1d62cc29d28..1853da94a46 100644 --- a/tests/baselines/reference/declFileFunctions.symbols +++ b/tests/baselines/reference/declFileFunctions.symbols @@ -64,50 +64,76 @@ export function fooWithTypePredicate(a: any): a is number { return true; } +export function fooWithTypePredicateAndMulitpleParams(a: any, b: any, c: any): a is number { +>fooWithTypePredicateAndMulitpleParams : Symbol(fooWithTypePredicateAndMulitpleParams, Decl(declFileFunctions_0.ts, 27, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 28, 54)) +>b : Symbol(b, Decl(declFileFunctions_0.ts, 28, 61)) +>c : Symbol(c, Decl(declFileFunctions_0.ts, 28, 69)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 28, 54)) + + return true; +} +export function fooWithTypeTypePredicateAndGeneric(a: any): a is T { +>fooWithTypeTypePredicateAndGeneric : Symbol(fooWithTypeTypePredicateAndGeneric, Decl(declFileFunctions_0.ts, 30, 1)) +>T : Symbol(T, Decl(declFileFunctions_0.ts, 31, 51)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 31, 54)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 31, 54)) +>T : Symbol(T, Decl(declFileFunctions_0.ts, 31, 51)) + + return true; +} +export function fooWithTypeTypePredicateAndRestParam(a: any, ...rest): a is number { +>fooWithTypeTypePredicateAndRestParam : Symbol(fooWithTypeTypePredicateAndRestParam, Decl(declFileFunctions_0.ts, 33, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 34, 53)) +>rest : Symbol(rest, Decl(declFileFunctions_0.ts, 34, 60)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 34, 53)) + + return true; +} /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { ->nonExportedFoo : Symbol(nonExportedFoo, Decl(declFileFunctions_0.ts, 27, 1)) +>nonExportedFoo : Symbol(nonExportedFoo, Decl(declFileFunctions_0.ts, 36, 1)) } /** This is comment for function signature*/ function nonExportedFooWithParameters(/** this is comment about a*/a: string, ->nonExportedFooWithParameters : Symbol(nonExportedFooWithParameters, Decl(declFileFunctions_0.ts, 31, 1)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 33, 38)) +>nonExportedFooWithParameters : Symbol(nonExportedFooWithParameters, Decl(declFileFunctions_0.ts, 40, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 42, 38)) /** this is comment for b*/ b: number) { ->b : Symbol(b, Decl(declFileFunctions_0.ts, 33, 77)) +>b : Symbol(b, Decl(declFileFunctions_0.ts, 42, 77)) var d = a; ->d : Symbol(d, Decl(declFileFunctions_0.ts, 36, 7)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 33, 38)) +>d : Symbol(d, Decl(declFileFunctions_0.ts, 45, 7)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 42, 38)) } function nonExportedFooWithRestParameters(a: string, ...rests: string[]) { ->nonExportedFooWithRestParameters : Symbol(nonExportedFooWithRestParameters, Decl(declFileFunctions_0.ts, 37, 1)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 38, 42)) ->rests : Symbol(rests, Decl(declFileFunctions_0.ts, 38, 52)) +>nonExportedFooWithRestParameters : Symbol(nonExportedFooWithRestParameters, Decl(declFileFunctions_0.ts, 46, 1)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 47, 42)) +>rests : Symbol(rests, Decl(declFileFunctions_0.ts, 47, 52)) return a + rests.join(""); ->a : Symbol(a, Decl(declFileFunctions_0.ts, 38, 42)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 47, 42)) >rests.join : Symbol(Array.join, Decl(lib.d.ts, 1035, 31)) ->rests : Symbol(rests, Decl(declFileFunctions_0.ts, 38, 52)) +>rests : Symbol(rests, Decl(declFileFunctions_0.ts, 47, 52)) >join : Symbol(Array.join, Decl(lib.d.ts, 1035, 31)) } function nonExportedFooWithOverloads(a: string): string; ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 42, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 49, 1), Decl(declFileFunctions_0.ts, 51, 56), Decl(declFileFunctions_0.ts, 52, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 51, 37)) function nonExportedFooWithOverloads(a: number): number; ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 43, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 49, 1), Decl(declFileFunctions_0.ts, 51, 56), Decl(declFileFunctions_0.ts, 52, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 52, 37)) function nonExportedFooWithOverloads(a: any): any { ->nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 40, 1), Decl(declFileFunctions_0.ts, 42, 56), Decl(declFileFunctions_0.ts, 43, 56)) ->a : Symbol(a, Decl(declFileFunctions_0.ts, 44, 37)) +>nonExportedFooWithOverloads : Symbol(nonExportedFooWithOverloads, Decl(declFileFunctions_0.ts, 49, 1), Decl(declFileFunctions_0.ts, 51, 56), Decl(declFileFunctions_0.ts, 52, 56)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 53, 37)) return a; ->a : Symbol(a, Decl(declFileFunctions_0.ts, 44, 37)) +>a : Symbol(a, Decl(declFileFunctions_0.ts, 53, 37)) } === tests/cases/compiler/declFileFunctions_1.ts === diff --git a/tests/baselines/reference/declFileFunctions.types b/tests/baselines/reference/declFileFunctions.types index e6ecc53b043..9ad974463b7 100644 --- a/tests/baselines/reference/declFileFunctions.types +++ b/tests/baselines/reference/declFileFunctions.types @@ -61,13 +61,42 @@ export function fooWithSingleOverload(a: any) { } export function fooWithTypePredicate(a: any): a is number { ->fooWithTypePredicate : (a: any) => boolean +>fooWithTypePredicate : (a: any) => a is number >a : any >a : any return true; >true : boolean } +export function fooWithTypePredicateAndMulitpleParams(a: any, b: any, c: any): a is number { +>fooWithTypePredicateAndMulitpleParams : (a: any, b: any, c: any) => a is number +>a : any +>b : any +>c : any +>a : any + + return true; +>true : boolean +} +export function fooWithTypeTypePredicateAndGeneric(a: any): a is T { +>fooWithTypeTypePredicateAndGeneric : (a: any) => a is T +>T : T +>a : any +>a : any +>T : T + + return true; +>true : boolean +} +export function fooWithTypeTypePredicateAndRestParam(a: any, ...rest): a is number { +>fooWithTypeTypePredicateAndRestParam : (a: any, ...rest: any[]) => a is number +>a : any +>rest : any[] +>a : any + + return true; +>true : boolean +} /** This comment should appear for nonExportedFoo*/ function nonExportedFoo() { diff --git a/tests/baselines/reference/isArray.types b/tests/baselines/reference/isArray.types index 8865ff73bc0..bc452b12bef 100644 --- a/tests/baselines/reference/isArray.types +++ b/tests/baselines/reference/isArray.types @@ -5,9 +5,9 @@ var maybeArray: number | number[]; if (Array.isArray(maybeArray)) { >Array.isArray(maybeArray) : boolean ->Array.isArray : (arg: any) => boolean +>Array.isArray : (arg: any) => arg is any[] >Array : ArrayConstructor ->isArray : (arg: any) => boolean +>isArray : (arg: any) => arg is any[] >maybeArray : number | number[] maybeArray.length; // OK diff --git a/tests/baselines/reference/typeGuardFunction.types b/tests/baselines/reference/typeGuardFunction.types index cf673f965f9..6cc278f122f 100644 --- a/tests/baselines/reference/typeGuardFunction.types +++ b/tests/baselines/reference/typeGuardFunction.types @@ -23,19 +23,19 @@ class C extends A { } declare function isA(p1: any): p1 is A; ->isA : (p1: any) => boolean +>isA : (p1: any) => p1 is A >p1 : any >p1 : any >A : A declare function isB(p1: any): p1 is B; ->isB : (p1: any) => boolean +>isB : (p1: any) => p1 is B >p1 : any >p1 : any >B : B declare function isC(p1: any): p1 is C; ->isC : (p1: any) => boolean +>isC : (p1: any) => p1 is C >p1 : any >p1 : any >C : C @@ -55,7 +55,7 @@ var b: B; // Basic if (isC(a)) { >isC(a) : boolean ->isC : (p1: any) => boolean +>isC : (p1: any) => p1 is C >a : A a.propC; @@ -71,7 +71,7 @@ var subType: C; if(isA(subType)) { >isA(subType) : boolean ->isA : (p1: any) => boolean +>isA : (p1: any) => p1 is A >subType : C subType.propC; @@ -88,7 +88,7 @@ var union: A | B; if(isA(union)) { >isA(union) : boolean ->isA : (p1: any) => boolean +>isA : (p1: any) => p1 is A >union : A | B union.propA; @@ -111,7 +111,7 @@ interface I1 { // 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 +>isC_multipleParams : (p1: any, p2: any) => p1 is C >p1 : any >p2 : any >p1 : any @@ -119,7 +119,7 @@ declare function isC_multipleParams(p1, p2): p1 is C; if (isC_multipleParams(a, 0)) { >isC_multipleParams(a, 0) : boolean ->isC_multipleParams : (p1: any, p2: any) => boolean +>isC_multipleParams : (p1: any, p2: any) => p1 is C >a : A >0 : number @@ -131,10 +131,10 @@ if (isC_multipleParams(a, 0)) { // Methods var obj: { ->obj : { func1(p1: A): boolean; } +>obj : { func1(p1: A): p1 is C; } func1(p1: A): p1 is C; ->func1 : (p1: A) => boolean +>func1 : (p1: A) => p1 is C >p1 : A >A : A >p1 : any @@ -144,7 +144,7 @@ class D { >D : D method1(p1: A): p1 is C { ->method1 : (p1: A) => boolean +>method1 : (p1: A) => p1 is C >p1 : A >A : A >p1 : any @@ -157,8 +157,8 @@ class D { // Arrow function let f1 = (p1: A): p1 is C => false; ->f1 : (p1: A) => boolean ->(p1: A): p1 is C => false : (p1: A) => boolean +>f1 : (p1: A) => p1 is C +>(p1: A): p1 is C => false : (p1: A) => p1 is C >p1 : A >A : A >p1 : any @@ -167,8 +167,8 @@ let f1 = (p1: A): p1 is C => false; // Function type declare function f2(p1: (p1: A) => p1 is C); ->f2 : (p1: (p1: A) => boolean) => any ->p1 : (p1: A) => boolean +>f2 : (p1: (p1: A) => p1 is C) => any +>p1 : (p1: A) => p1 is C >p1 : A >A : A >p1 : any @@ -177,8 +177,8 @@ declare function f2(p1: (p1: A) => p1 is 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 +>f2 : (p1: (p1: A) => p1 is C) => any +>function(p1: A): p1 is C { return true;} : (p1: A) => p1 is C >p1 : A >A : A >p1 : any @@ -198,21 +198,21 @@ acceptingBoolean(isA(a)); >acceptingBoolean(isA(a)) : any >acceptingBoolean : (a: boolean) => any >isA(a) : boolean ->isA : (p1: any) => boolean +>isA : (p1: any) => p1 is A >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 +>acceptingTypeGuardFunction : (p1: (item: any) => item is A) => any +>p1 : (item: any) => item is A >item : any >item : any >A : A acceptingTypeGuardFunction(isA); >acceptingTypeGuardFunction(isA) : any ->acceptingTypeGuardFunction : (p1: (item: any) => boolean) => any ->isA : (p1: any) => boolean +>acceptingTypeGuardFunction : (p1: (item: any) => item is A) => any +>isA : (p1: any) => p1 is A // Binary expressions let union2: C | B; @@ -225,7 +225,7 @@ let union3: boolean | B = isA(union2) || union2; >B : B >isA(union2) || union2 : boolean | B >isA(union2) : boolean ->isA : (p1: any) => boolean +>isA : (p1: any) => p1 is A >union2 : B | C >union2 : B diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index 499a51035f2..b178b02c6b4 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -12,15 +12,15 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(46,56) tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(60,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(65,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7): error TS2339: Property 'propB' does not exist on type 'A'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,46): error TS2345: Argument of type '(p1: any) => boolean' is not assignable to parameter of type '(p1: any) => boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => 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(79,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(79,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'. Signature '(p1: any, p2: any): boolean' must have a type predicate. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(85,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(85,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. 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(91,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(91,1): error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. @@ -141,7 +141,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 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: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => 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'. @@ -149,7 +149,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 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: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'. !!! error TS2322: Signature '(p1: any, p2: any): boolean' must have a type predicate. return true; }; @@ -158,7 +158,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 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 '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. !!! 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; @@ -168,7 +168,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 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'. +!!! error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. return true; }; diff --git a/tests/baselines/reference/typeGuardFunctionGenerics.types b/tests/baselines/reference/typeGuardFunctionGenerics.types index 77162e55a40..c4655e71f0c 100644 --- a/tests/baselines/reference/typeGuardFunctionGenerics.types +++ b/tests/baselines/reference/typeGuardFunctionGenerics.types @@ -23,13 +23,13 @@ class C extends A { } declare function isB(p1): p1 is B; ->isB : (p1: any) => boolean +>isB : (p1: any) => p1 is B >p1 : any >p1 : any >B : B declare function isC(p1): p1 is C; ->isC : (p1: any) => boolean +>isC : (p1: any) => p1 is C >p1 : any >p1 : any >C : C @@ -48,7 +48,7 @@ declare function funA(p1: (p1) => T): T; >T : T declare function funB(p1: (p1) => T, p2: any): p2 is T; ->funB : (p1: (p1: any) => T, p2: any) => boolean +>funB : (p1: (p1: any) => T, p2: any) => p2 is T >T : T >p1 : (p1: any) => T >p1 : any @@ -58,18 +58,18 @@ declare function funB(p1: (p1) => T, p2: any): p2 is T; >T : T declare function funC(p1: (p1) => p1 is T): T; ->funC : (p1: (p1: any) => boolean) => T +>funC : (p1: (p1: any) => p1 is T) => T >T : T ->p1 : (p1: any) => boolean +>p1 : (p1: any) => p1 is T >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 +>funD : (p1: (p1: any) => p1 is T, p2: any) => p2 is T >T : T ->p1 : (p1: any) => boolean +>p1 : (p1: any) => p1 is T >p1 : any >p1 : any >T : T @@ -78,10 +78,10 @@ declare function funD(p1: (p1) => p1 is T, p2: any): p2 is T; >T : T declare function funE(p1: (p1) => p1 is T, p2: U): T; ->funE : (p1: (p1: any) => boolean, p2: U) => T +>funE : (p1: (p1: any) => p1 is T, p2: U) => T >T : T >U : U ->p1 : (p1: any) => boolean +>p1 : (p1: any) => p1 is T >p1 : any >p1 : any >T : T @@ -97,11 +97,11 @@ let test1: boolean = funA(isB); >test1 : boolean >funA(isB) : boolean >funA : (p1: (p1: any) => T) => T ->isB : (p1: any) => boolean +>isB : (p1: any) => p1 is B if (funB(retC, a)) { >funB(retC, a) : boolean ->funB : (p1: (p1: any) => T, p2: any) => boolean +>funB : (p1: (p1: any) => T, p2: any) => p2 is T >retC : (x: any) => C >a : A @@ -114,13 +114,13 @@ let test2: B = funC(isB); >test2 : B >B : B >funC(isB) : B ->funC : (p1: (p1: any) => boolean) => T ->isB : (p1: any) => boolean +>funC : (p1: (p1: any) => p1 is T) => T +>isB : (p1: any) => p1 is B if (funD(isC, a)) { >funD(isC, a) : boolean ->funD : (p1: (p1: any) => boolean, p2: any) => boolean ->isC : (p1: any) => boolean +>funD : (p1: (p1: any) => p1 is T, p2: any) => p2 is T +>isC : (p1: any) => p1 is C >a : A a.propC; @@ -132,7 +132,7 @@ 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 +>funE : (p1: (p1: any) => p1 is T, p2: U) => T +>isB : (p1: any) => p1 is B >1 : number diff --git a/tests/baselines/reference/typeGuardOfFormIsType.types b/tests/baselines/reference/typeGuardOfFormIsType.types index b14e5e22910..e2059be7b63 100644 --- a/tests/baselines/reference/typeGuardOfFormIsType.types +++ b/tests/baselines/reference/typeGuardOfFormIsType.types @@ -29,7 +29,7 @@ var strOrNum: string | number; >strOrNum : string | number function isC1(x: any): x is C1 { ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >x : any >x : any >C1 : C1 @@ -39,7 +39,7 @@ function isC1(x: any): x is C1 { } function isC2(x: any): x is C2 { ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >x : any >x : any >C2 : C2 @@ -49,7 +49,7 @@ function isC2(x: any): x is C2 { } function isD1(x: any): x is D1 { ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >x : any >x : any >D1 : D1 @@ -68,7 +68,7 @@ str = isC1(c1Orc2) && c1Orc2.p1; // C1 >str : string >isC1(c1Orc2) && c1Orc2.p1 : string >isC1(c1Orc2) : boolean ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >c1Orc2 : C1 | C2 >c1Orc2.p1 : string >c1Orc2 : C1 @@ -79,7 +79,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2 >num : number >isC2(c1Orc2) && c1Orc2.p2 : number >isC2(c1Orc2) : boolean ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >c1Orc2 : C1 | C2 >c1Orc2.p2 : number >c1Orc2 : C2 @@ -90,7 +90,7 @@ str = isD1(c1Orc2) && c1Orc2.p1; // D1 >str : string >isD1(c1Orc2) && c1Orc2.p1 : string >isD1(c1Orc2) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c1Orc2 : C1 | C2 >c1Orc2.p1 : string >c1Orc2 : D1 @@ -101,7 +101,7 @@ num = isD1(c1Orc2) && c1Orc2.p3; // D1 >num : number >isD1(c1Orc2) && c1Orc2.p3 : number >isD1(c1Orc2) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c1Orc2 : C1 | C2 >c1Orc2.p3 : number >c1Orc2 : D1 @@ -117,7 +117,7 @@ num = isC2(c2Ord1) && c2Ord1.p2; // C2 >num : number >isC2(c2Ord1) && c2Ord1.p2 : number >isC2(c2Ord1) : boolean ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >c2Ord1 : C2 | D1 >c2Ord1.p2 : number >c2Ord1 : C2 @@ -128,7 +128,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1 >num : number >isD1(c2Ord1) && c2Ord1.p3 : number >isD1(c2Ord1) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c2Ord1 : C2 | D1 >c2Ord1.p3 : number >c2Ord1 : D1 @@ -139,7 +139,7 @@ str = isD1(c2Ord1) && c2Ord1.p1; // D1 >str : string >isD1(c2Ord1) && c2Ord1.p1 : string >isD1(c2Ord1) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c2Ord1 : C2 | D1 >c2Ord1.p1 : string >c2Ord1 : D1 @@ -151,7 +151,7 @@ var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 >D1 : D1 >isC1(c2Ord1) && c2Ord1 : D1 >isC1(c2Ord1) : boolean ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >c2Ord1 : C2 | D1 >c2Ord1 : D1 diff --git a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types index 3a659d71163..ea169e95413 100644 --- a/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types +++ b/tests/baselines/reference/typeGuardOfFormIsTypeOnInterfaces.types @@ -48,7 +48,7 @@ var strOrNum: string | number; function isC1(x: any): x is C1 { ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >x : any >x : any >C1 : C1 @@ -58,7 +58,7 @@ function isC1(x: any): x is C1 { } function isC2(x: any): x is C2 { ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >x : any >x : any >C2 : C2 @@ -68,7 +68,7 @@ function isC2(x: any): x is C2 { } function isD1(x: any): x is D1 { ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >x : any >x : any >D1 : D1 @@ -99,7 +99,7 @@ str = isC1(c1Orc2) && c1Orc2.p1; // C1 >str : string >isC1(c1Orc2) && c1Orc2.p1 : string >isC1(c1Orc2) : boolean ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >c1Orc2 : C1 | C2 >c1Orc2.p1 : string >c1Orc2 : C1 @@ -110,7 +110,7 @@ num = isC2(c1Orc2) && c1Orc2.p2; // C2 >num : number >isC2(c1Orc2) && c1Orc2.p2 : number >isC2(c1Orc2) : boolean ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >c1Orc2 : C1 | C2 >c1Orc2.p2 : number >c1Orc2 : C2 @@ -121,7 +121,7 @@ str = isD1(c1Orc2) && c1Orc2.p1; // D1 >str : string >isD1(c1Orc2) && c1Orc2.p1 : string >isD1(c1Orc2) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c1Orc2 : C1 | C2 >c1Orc2.p1 : string >c1Orc2 : D1 @@ -132,7 +132,7 @@ num = isD1(c1Orc2) && c1Orc2.p3; // D1 >num : number >isD1(c1Orc2) && c1Orc2.p3 : number >isD1(c1Orc2) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c1Orc2 : C1 | C2 >c1Orc2.p3 : number >c1Orc2 : D1 @@ -148,7 +148,7 @@ num = isC2(c2Ord1) && c2Ord1.p2; // C2 >num : number >isC2(c2Ord1) && c2Ord1.p2 : number >isC2(c2Ord1) : boolean ->isC2 : (x: any) => boolean +>isC2 : (x: any) => x is C2 >c2Ord1 : C2 | D1 >c2Ord1.p2 : number >c2Ord1 : C2 @@ -159,7 +159,7 @@ num = isD1(c2Ord1) && c2Ord1.p3; // D1 >num : number >isD1(c2Ord1) && c2Ord1.p3 : number >isD1(c2Ord1) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c2Ord1 : C2 | D1 >c2Ord1.p3 : number >c2Ord1 : D1 @@ -170,7 +170,7 @@ str = isD1(c2Ord1) && c2Ord1.p1; // D1 >str : string >isD1(c2Ord1) && c2Ord1.p1 : string >isD1(c2Ord1) : boolean ->isD1 : (x: any) => boolean +>isD1 : (x: any) => x is D1 >c2Ord1 : C2 | D1 >c2Ord1.p1 : string >c2Ord1 : D1 @@ -182,7 +182,7 @@ var r2: C2 | D1 = isC1(c2Ord1) && c2Ord1; // C2 | D1 >D1 : D1 >isC1(c2Ord1) && c2Ord1 : D1 >isC1(c2Ord1) : boolean ->isC1 : (x: any) => boolean +>isC1 : (x: any) => x is C1 >c2Ord1 : C2 | D1 >c2Ord1 : D1 From 43307edd4a8c97ca329a1175bf1a7150750c86fc Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Thu, 9 Jul 2015 20:27:05 +0300 Subject: [PATCH 23/29] fixed issue https://github.com/Microsoft/TypeScript/issues/3486 --- src/compiler/checker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b34952f3ae..d64a294cebf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14718,10 +14718,10 @@ namespace ts { checkGrammarForAtLeastOneTypeArgument(node, typeArguments); } - function checkGrammarForOmittedArgument(node: CallExpression, arguments: NodeArray): boolean { - if (arguments) { + function checkGrammarForOmittedArgument(node: CallExpression, args: NodeArray): boolean { + if (args) { let sourceFile = getSourceFileOfNode(node); - for (let arg of arguments) { + for (let arg of args) { if (arg.kind === SyntaxKind.OmittedExpression) { return grammarErrorAtPos(sourceFile, arg.pos, 0, Diagnostics.Argument_expression_expected); } @@ -14729,9 +14729,9 @@ namespace ts { } } - function checkGrammarArguments(node: CallExpression, arguments: NodeArray): boolean { - return checkGrammarForDisallowedTrailingComma(arguments) || - checkGrammarForOmittedArgument(node, arguments); + function checkGrammarArguments(node: CallExpression, args: NodeArray): boolean { + return checkGrammarForDisallowedTrailingComma(args) || + checkGrammarForOmittedArgument(node, args); } function checkGrammarHeritageClause(node: HeritageClause): boolean { From f37fc1d42ef7805ba029bbca201299863d49c050 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 9 Jul 2015 11:31:08 -0700 Subject: [PATCH 24/29] Infer types to statics in a class expression --- 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 1b34952f3ae..6c0b74c0b48 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5491,7 +5491,7 @@ namespace ts { } } else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) || - (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) { + (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class))) { // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members if (isInProcess(source, target)) { return; From f56298a0cd231905172fcdeb7bc62f16c8632ed2 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 9 Jul 2015 11:31:24 -0700 Subject: [PATCH 25/29] Add a test --- ...ypeArgumentInferenceWithClassExpression.js | 22 ++++++++++++++++++ ...gumentInferenceWithClassExpression.symbols | 19 +++++++++++++++ ...ArgumentInferenceWithClassExpression.types | 23 +++++++++++++++++++ ...ypeArgumentInferenceWithClassExpression.ts | 5 ++++ 4 files changed, 69 insertions(+) create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression.js create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression.types create mode 100644 tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.js new file mode 100644 index 00000000000..cc0bf971473 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.js @@ -0,0 +1,22 @@ +//// [typeArgumentInferenceWithClassExpression.ts] +function foo(x = class { static prop: T }): T { + return undefined; +} + +foo(class { static prop = "hello" }).length; + +//// [typeArgumentInferenceWithClassExpression.js] +function foo(x) { + if (x === void 0) { x = (function () { + function class_1() { + } + return class_1; + })(); } + return undefined; +} +foo((function () { + function class_2() { + } + class_2.prop = "hello"; + return class_2; +})()).length; diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols new file mode 100644 index 00000000000..dac982595cb --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts === +function foo(x = class { static prop: T }): T { +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 0)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) +>x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 16)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 27)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) + + return undefined; +>undefined : Symbol(undefined) +} + +foo(class { static prop = "hello" }).length; +>foo(class { static prop = "hello" }).length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 0)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression.ts, 4, 11)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) + diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.types b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.types new file mode 100644 index 00000000000..3eab8a4ab62 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression.types @@ -0,0 +1,23 @@ +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts === +function foo(x = class { static prop: T }): T { +>foo : (x?: typeof (Anonymous class)) => T +>T : T +>x : typeof (Anonymous class) +>class { static prop: T } : typeof (Anonymous class) +>prop : T +>T : T +>T : T + + return undefined; +>undefined : undefined +} + +foo(class { static prop = "hello" }).length; +>foo(class { static prop = "hello" }).length : number +>foo(class { static prop = "hello" }) : string +>foo : (x?: typeof (Anonymous class)) => T +>class { static prop = "hello" } : typeof (Anonymous class) +>prop : string +>"hello" : string +>length : number + diff --git a/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts new file mode 100644 index 00000000000..21ca07ea2a2 --- /dev/null +++ b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts @@ -0,0 +1,5 @@ +function foo(x = class { static prop: T }): T { + return undefined; +} + +foo(class { static prop = "hello" }).length; \ No newline at end of file From 4e644e5ab849e98da526f733b2ce938d981d2719 Mon Sep 17 00:00:00 2001 From: Tingan Ho Date: Fri, 10 Jul 2015 03:27:31 +0800 Subject: [PATCH 26/29] Fixes spacing issue --- 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 03a3f7efa9b..08f4605ebe2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1958,7 +1958,7 @@ namespace ts { returnType = signature.typePredicate.type; } else { - returnType = getReturnTypeOfSignature(signature); + returnType = getReturnTypeOfSignature(signature); } buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack); } From 8bb956eb917c07058773b01d77c7e586b7fa8571 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 9 Jul 2015 14:41:08 -0700 Subject: [PATCH 27/29] More tests --- ...eArgumentInferenceWithClassExpression1.js} | 4 ++-- ...mentInferenceWithClassExpression1.symbols} | 18 +++++++------- ...gumentInferenceWithClassExpression1.types} | 2 +- ...ntInferenceWithClassExpression2.errors.txt | 16 +++++++++++++ ...peArgumentInferenceWithClassExpression2.js | 24 +++++++++++++++++++ ...peArgumentInferenceWithClassExpression3.js | 22 +++++++++++++++++ ...umentInferenceWithClassExpression3.symbols | 19 +++++++++++++++ ...rgumentInferenceWithClassExpression3.types | 23 ++++++++++++++++++ ...eArgumentInferenceWithClassExpression1.ts} | 0 ...peArgumentInferenceWithClassExpression2.ts | 6 +++++ ...peArgumentInferenceWithClassExpression3.ts | 5 ++++ 11 files changed, 127 insertions(+), 12 deletions(-) rename tests/baselines/reference/{typeArgumentInferenceWithClassExpression.js => typeArgumentInferenceWithClassExpression1.js} (76%) rename tests/baselines/reference/{typeArgumentInferenceWithClassExpression.symbols => typeArgumentInferenceWithClassExpression1.symbols} (58%) rename tests/baselines/reference/{typeArgumentInferenceWithClassExpression.types => typeArgumentInferenceWithClassExpression1.types} (91%) create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression2.errors.txt create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression3.js create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression3.symbols create mode 100644 tests/baselines/reference/typeArgumentInferenceWithClassExpression3.types rename tests/cases/conformance/es6/classExpressions/{typeArgumentInferenceWithClassExpression.ts => typeArgumentInferenceWithClassExpression1.ts} (100%) create mode 100644 tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts create mode 100644 tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js similarity index 76% rename from tests/baselines/reference/typeArgumentInferenceWithClassExpression.js rename to tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js index cc0bf971473..25ce3743fa2 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.js +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js @@ -1,11 +1,11 @@ -//// [typeArgumentInferenceWithClassExpression.ts] +//// [typeArgumentInferenceWithClassExpression1.ts] function foo(x = class { static prop: T }): T { return undefined; } foo(class { static prop = "hello" }).length; -//// [typeArgumentInferenceWithClassExpression.js] +//// [typeArgumentInferenceWithClassExpression1.js] function foo(x) { if (x === void 0) { x = (function () { function class_1() { diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.symbols similarity index 58% rename from tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols rename to tests/baselines/reference/typeArgumentInferenceWithClassExpression1.symbols index dac982595cb..ceb97a73af8 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.symbols +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.symbols @@ -1,11 +1,11 @@ -=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts === +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts === function foo(x = class { static prop: T }): T { ->foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 0)) ->T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) ->x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 16)) ->prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 27)) ->T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) ->T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 13)) +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 0)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13)) +>x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 16)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 27)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 13)) return undefined; >undefined : Symbol(undefined) @@ -13,7 +13,7 @@ function foo(x = class { static prop: T }): T { foo(class { static prop = "hello" }).length; >foo(class { static prop = "hello" }).length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) ->foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression.ts, 0, 0)) ->prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression.ts, 4, 11)) +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression1.ts, 0, 0)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression1.ts, 4, 11)) >length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.types b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.types similarity index 91% rename from tests/baselines/reference/typeArgumentInferenceWithClassExpression.types rename to tests/baselines/reference/typeArgumentInferenceWithClassExpression1.types index 3eab8a4ab62..63ee1309383 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithClassExpression.types +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.types @@ -1,4 +1,4 @@ -=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts === +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts === function foo(x = class { static prop: T }): T { >foo : (x?: typeof (Anonymous class)) => T >T : T diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.errors.txt b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.errors.txt new file mode 100644 index 00000000000..c630944306b --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.errors.txt @@ -0,0 +1,16 @@ +tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts(6,5): error TS2345: Argument of type 'typeof (Anonymous class)' is not assignable to parameter of type 'typeof (Anonymous class)'. + Type '(Anonymous class)' is not assignable to type 'foo<{}>.'. + Property 'prop' is missing in type '(Anonymous class)'. + + +==== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts (1 errors) ==== + function foo(x = class { prop: T }): T { + return undefined; + } + + // Should not infer string because it is a static property + foo(class { static prop = "hello" }).length; + ~~~~~ +!!! error TS2345: Argument of type 'typeof (Anonymous class)' is not assignable to parameter of type 'typeof (Anonymous class)'. +!!! error TS2345: Type '(Anonymous class)' is not assignable to type 'foo<{}>.'. +!!! error TS2345: Property 'prop' is missing in type '(Anonymous class)'. \ No newline at end of file diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js new file mode 100644 index 00000000000..c4a7872b016 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js @@ -0,0 +1,24 @@ +//// [typeArgumentInferenceWithClassExpression2.ts] +function foo(x = class { prop: T }): T { + return undefined; +} + +// Should not infer string because it is a static property +foo(class { static prop = "hello" }).length; + +//// [typeArgumentInferenceWithClassExpression2.js] +function foo(x) { + if (x === void 0) { x = (function () { + function class_1() { + } + return class_1; + })(); } + return undefined; +} +// Should not infer string because it is a static property +foo((function () { + function class_2() { + } + class_2.prop = "hello"; + return class_2; +})()).length; diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.js new file mode 100644 index 00000000000..f3a3470e1c3 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.js @@ -0,0 +1,22 @@ +//// [typeArgumentInferenceWithClassExpression3.ts] +function foo(x = class { prop: T }): T { + return undefined; +} + +foo(class { prop = "hello" }).length; + +//// [typeArgumentInferenceWithClassExpression3.js] +function foo(x) { + if (x === void 0) { x = (function () { + function class_1() { + } + return class_1; + })(); } + return undefined; +} +foo((function () { + function class_2() { + this.prop = "hello"; + } + return class_2; +})()).length; diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.symbols b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.symbols new file mode 100644 index 00000000000..aedb0230fd6 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts === +function foo(x = class { prop: T }): T { +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 0)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13)) +>x : Symbol(x, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 16)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 27)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13)) +>T : Symbol(T, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 13)) + + return undefined; +>undefined : Symbol(undefined) +} + +foo(class { prop = "hello" }).length; +>foo(class { prop = "hello" }).length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>foo : Symbol(foo, Decl(typeArgumentInferenceWithClassExpression3.ts, 0, 0)) +>prop : Symbol((Anonymous class).prop, Decl(typeArgumentInferenceWithClassExpression3.ts, 4, 11)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) + diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.types b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.types new file mode 100644 index 00000000000..9a2bddd9296 --- /dev/null +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression3.types @@ -0,0 +1,23 @@ +=== tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts === +function foo(x = class { prop: T }): T { +>foo : (x?: typeof (Anonymous class)) => T +>T : T +>x : typeof (Anonymous class) +>class { prop: T } : typeof (Anonymous class) +>prop : T +>T : T +>T : T + + return undefined; +>undefined : undefined +} + +foo(class { prop = "hello" }).length; +>foo(class { prop = "hello" }).length : number +>foo(class { prop = "hello" }) : string +>foo : (x?: typeof (Anonymous class)) => T +>class { prop = "hello" } : typeof (Anonymous class) +>prop : string +>"hello" : string +>length : number + diff --git a/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts similarity index 100% rename from tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression.ts rename to tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression1.ts diff --git a/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts new file mode 100644 index 00000000000..d7a901ae951 --- /dev/null +++ b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression2.ts @@ -0,0 +1,6 @@ +function foo(x = class { prop: T }): T { + return undefined; +} + +// Should not infer string because it is a static property +foo(class { static prop = "hello" }).length; \ No newline at end of file diff --git a/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts new file mode 100644 index 00000000000..d29b7007664 --- /dev/null +++ b/tests/cases/conformance/es6/classExpressions/typeArgumentInferenceWithClassExpression3.ts @@ -0,0 +1,5 @@ +function foo(x = class { prop: T }): T { + return undefined; +} + +foo(class { prop = "hello" }).length; \ No newline at end of file From 9353a60cffd16d79125712eac31b81340cd01c7b Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 9 Jul 2015 16:09:50 -0700 Subject: [PATCH 28/29] Readd className to SVGStylable for compatibility --- src/lib/dom.generated.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 53e086a9dc4..19133b68b4c 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -12536,6 +12536,7 @@ interface SVGLocatable { } interface SVGStylable { + className: any; style: CSSStyleDeclaration; } From 89c44f52a34e3dd72f7e12ec40dbff5c16ed89b8 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 9 Jul 2015 16:48:39 -0700 Subject: [PATCH 29/29] Add className property in SVGElement --- src/lib/dom.generated.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 19133b68b4c..32e8fb45ce4 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -8715,6 +8715,7 @@ declare var SVGDescElement: { interface SVGElement extends Element { id: string; + className: any; onclick: (ev: MouseEvent) => any; ondblclick: (ev: MouseEvent) => any; onfocusin: (ev: FocusEvent) => any;