From 6e87078540110011aee9cae1f9a5dfcbfc387789 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 6 Jun 2017 14:48:40 -0700 Subject: [PATCH] Added tests and improve type of new expression --- src/compiler/checker.ts | 4 +- .../reference/constructorFunctions.symbols | 76 ++++++++++++ .../reference/constructorFunctions.types | 114 ++++++++++++++++++ .../reference/jsConstructorFunction.symbols | 56 --------- .../reference/jsConstructorFunction.types | 81 ------------- tests/cases/compiler/jsConstructorFunction.ts | 22 ---- .../conformance/salsa/constructorFunctions.ts | 36 ++++++ 7 files changed, 228 insertions(+), 161 deletions(-) create mode 100644 tests/baselines/reference/constructorFunctions.symbols create mode 100644 tests/baselines/reference/constructorFunctions.types delete mode 100644 tests/baselines/reference/jsConstructorFunction.symbols delete mode 100644 tests/baselines/reference/jsConstructorFunction.types delete mode 100644 tests/cases/compiler/jsConstructorFunction.ts create mode 100644 tests/cases/conformance/salsa/constructorFunctions.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b1a836fe865..c8705c5f29e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16142,7 +16142,7 @@ namespace ts { function getInferredClassType(symbol: Symbol) { const links = getSymbolLinks(symbol); if (!links.inferredClassType) { - links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); + links.inferredClassType = createAnonymousType(symbol, symbol.members || emptySymbols, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); } return links.inferredClassType; } @@ -16182,7 +16182,7 @@ namespace ts { if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { funcSymbol = getSymbolOfNode((funcSymbol.valueDeclaration).initializer); } - if (funcSymbol && funcSymbol.members && funcSymbol.flags & SymbolFlags.Function) { + if (funcSymbol && funcSymbol.flags & SymbolFlags.Function && (funcSymbol.members || getJSDocClassTag(funcSymbol.valueDeclaration))) { return getInferredClassType(funcSymbol); } else if (noImplicitAny) { diff --git a/tests/baselines/reference/constructorFunctions.symbols b/tests/baselines/reference/constructorFunctions.symbols new file mode 100644 index 00000000000..f55075794ab --- /dev/null +++ b/tests/baselines/reference/constructorFunctions.symbols @@ -0,0 +1,76 @@ +=== tests/cases/conformance/salsa/index.js === +function C1() { +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + + if (!(this instanceof C1)) return new C1(); +>C1 : Symbol(C1, Decl(index.js, 0, 0)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + + this.x = 1; +>x : Symbol(C1.x, Decl(index.js, 1, 47)) +} + +const c1_v1 = C1(); +>c1_v1 : Symbol(c1_v1, Decl(index.js, 5, 5)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + +const c1_v2 = new C1(); +>c1_v2 : Symbol(c1_v2, Decl(index.js, 6, 5)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + +var C2 = function () { +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + + if (!(this instanceof C2)) return new C2(); +>C2 : Symbol(C2, Decl(index.js, 8, 3)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + + this.x = 1; +>x : Symbol(C2.x, Decl(index.js, 9, 47)) + +}; + +const c2_v1 = C2(); +>c2_v1 : Symbol(c2_v1, Decl(index.js, 13, 5)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + +const c2_v2 = new C2(); +>c2_v2 : Symbol(c2_v2, Decl(index.js, 14, 5)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + +/** @class */ +function C3() { +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + + if (!(this instanceof C3)) return new C3(); +>C3 : Symbol(C3, Decl(index.js, 14, 23)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +}; + +const c3_v1 = C3(); +>c3_v1 : Symbol(c3_v1, Decl(index.js, 21, 5)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +const c3_v2 = new C3(); +>c3_v2 : Symbol(c3_v2, Decl(index.js, 22, 5)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +/** @class */ +var C4 = function () { +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + + if (!(this instanceof C4)) return new C4(); +>C4 : Symbol(C4, Decl(index.js, 25, 3)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + +}; + +const c4_v1 = C4(); +>c4_v1 : Symbol(c4_v1, Decl(index.js, 29, 5)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + +const c4_v2 = new C4(); +>c4_v2 : Symbol(c4_v2, Decl(index.js, 30, 5)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + diff --git a/tests/baselines/reference/constructorFunctions.types b/tests/baselines/reference/constructorFunctions.types new file mode 100644 index 00000000000..3429758b017 --- /dev/null +++ b/tests/baselines/reference/constructorFunctions.types @@ -0,0 +1,114 @@ +=== tests/cases/conformance/salsa/index.js === +function C1() { +>C1 : () => typeof C1 + + if (!(this instanceof C1)) return new C1(); +>!(this instanceof C1) : boolean +>(this instanceof C1) : boolean +>this instanceof C1 : boolean +>this : any +>C1 : () => typeof C1 +>new C1() : { x: number; } +>C1 : () => typeof C1 + + this.x = 1; +>this.x = 1 : 1 +>this.x : any +>this : any +>x : any +>1 : 1 +} + +const c1_v1 = C1(); +>c1_v1 : { x: number; } +>C1() : { x: number; } +>C1 : () => typeof C1 + +const c1_v2 = new C1(); +>c1_v2 : { x: number; } +>new C1() : { x: number; } +>C1 : () => typeof C1 + +var C2 = function () { +>C2 : () => any +>function () { if (!(this instanceof C2)) return new C2(); this.x = 1;} : () => any + + if (!(this instanceof C2)) return new C2(); +>!(this instanceof C2) : boolean +>(this instanceof C2) : boolean +>this instanceof C2 : boolean +>this : any +>C2 : () => any +>new C2() : { x: number; } +>C2 : () => any + + this.x = 1; +>this.x = 1 : 1 +>this.x : any +>this : any +>x : any +>1 : 1 + +}; + +const c2_v1 = C2(); +>c2_v1 : { x: number; } +>C2() : { x: number; } +>C2 : () => any + +const c2_v2 = new C2(); +>c2_v2 : { x: number; } +>new C2() : { x: number; } +>C2 : () => any + +/** @class */ +function C3() { +>C3 : () => typeof C3 + + if (!(this instanceof C3)) return new C3(); +>!(this instanceof C3) : boolean +>(this instanceof C3) : boolean +>this instanceof C3 : boolean +>this : any +>C3 : () => typeof C3 +>new C3() : {} +>C3 : () => typeof C3 + +}; + +const c3_v1 = C3(); +>c3_v1 : {} +>C3() : {} +>C3 : () => typeof C3 + +const c3_v2 = new C3(); +>c3_v2 : {} +>new C3() : {} +>C3 : () => typeof C3 + +/** @class */ +var C4 = function () { +>C4 : () => any +>function () { if (!(this instanceof C4)) return new C4();} : () => any + + if (!(this instanceof C4)) return new C4(); +>!(this instanceof C4) : boolean +>(this instanceof C4) : boolean +>this instanceof C4 : boolean +>this : any +>C4 : () => any +>new C4() : {} +>C4 : () => any + +}; + +const c4_v1 = C4(); +>c4_v1 : {} +>C4() : {} +>C4 : () => any + +const c4_v2 = new C4(); +>c4_v2 : {} +>new C4() : {} +>C4 : () => any + diff --git a/tests/baselines/reference/jsConstructorFunction.symbols b/tests/baselines/reference/jsConstructorFunction.symbols deleted file mode 100644 index d4954b1abdc..00000000000 --- a/tests/baselines/reference/jsConstructorFunction.symbols +++ /dev/null @@ -1,56 +0,0 @@ -=== tests/cases/compiler/index.js === -var Person = function (firstNameOrPojo, lastName) { ->Person : Symbol(Person, Decl(index.js, 0, 3)) ->firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) ->lastName : Symbol(lastName, Decl(index.js, 0, 39)) - - if (typeof firstNameOrPojo === "string") { ->firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) - - this.firstName = firstNameOrPojo; ->firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) ->firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) - - this.lastName = lastName; ->lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) ->lastName : Symbol(lastName, Decl(index.js, 0, 39)) - - } else { - return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); ->Person : Symbol(Person, Decl(index.js, 0, 3)) ->firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) ->firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) - } -}; - -Person.prototype.greet = function greet() { ->Person.prototype : Symbol(Person.greet, Decl(index.js, 8, 2)) ->Person : Symbol(Person, Decl(index.js, 0, 3)) ->prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) ->greet : Symbol(Person.greet, Decl(index.js, 8, 2)) ->greet : Symbol(greet, Decl(index.js, 10, 24)) - - return `Hello, I am ${this.firstName} ${this.lastName}.`; ->this.firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) ->this : Symbol(Person, Decl(index.js, 0, 12)) ->firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) ->this.lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) ->this : Symbol(Person, Decl(index.js, 0, 12)) ->lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) - -}; - -var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); ->fred : Symbol(fred, Decl(index.js, 14, 3)) ->Person : Symbol(Person, Decl(index.js, 0, 3)) ->firstName : Symbol(firstName, Decl(index.js, 14, 23)) ->lastName : Symbol(lastName, Decl(index.js, 14, 42)) - -console.log(fred.greet()); ->console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) ->console : Symbol(console, Decl(lib.dom.d.ts, --, --)) ->log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) ->fred.greet : Symbol(Person.greet, Decl(index.js, 8, 2)) ->fred : Symbol(fred, Decl(index.js, 14, 3)) ->greet : Symbol(Person.greet, Decl(index.js, 8, 2)) - diff --git a/tests/baselines/reference/jsConstructorFunction.types b/tests/baselines/reference/jsConstructorFunction.types deleted file mode 100644 index 3c2854ac87f..00000000000 --- a/tests/baselines/reference/jsConstructorFunction.types +++ /dev/null @@ -1,81 +0,0 @@ -=== tests/cases/compiler/index.js === -var Person = function (firstNameOrPojo, lastName) { ->Person : (firstNameOrPojo: any, lastName: any) => any ->function (firstNameOrPojo, lastName) { if (typeof firstNameOrPojo === "string") { this.firstName = firstNameOrPojo; this.lastName = lastName; } else { return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); }} : (firstNameOrPojo: any, lastName: any) => any ->firstNameOrPojo : any ->lastName : any - - if (typeof firstNameOrPojo === "string") { ->typeof firstNameOrPojo === "string" : boolean ->typeof firstNameOrPojo : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" ->firstNameOrPojo : any ->"string" : "string" - - this.firstName = firstNameOrPojo; ->this.firstName = firstNameOrPojo : string ->this.firstName : any ->this : any ->firstName : any ->firstNameOrPojo : string - - this.lastName = lastName; ->this.lastName = lastName : any ->this.lastName : any ->this : any ->lastName : any ->lastName : any - - } else { - return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); ->new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName) : { firstName: string; lastName: any; greet: () => string; } ->Person : (firstNameOrPojo: any, lastName: any) => any ->firstNameOrPojo.firstName : any ->firstNameOrPojo : any ->firstName : any ->firstNameOrPojo.lastName : any ->firstNameOrPojo : any ->lastName : any - } -}; - -Person.prototype.greet = function greet() { ->Person.prototype.greet = function greet() { return `Hello, I am ${this.firstName} ${this.lastName}.`;} : () => string ->Person.prototype.greet : any ->Person.prototype : any ->Person : (firstNameOrPojo: any, lastName: any) => any ->prototype : any ->greet : any ->function greet() { return `Hello, I am ${this.firstName} ${this.lastName}.`;} : () => string ->greet : () => string - - return `Hello, I am ${this.firstName} ${this.lastName}.`; ->`Hello, I am ${this.firstName} ${this.lastName}.` : string ->this.firstName : string ->this : { firstName: string; lastName: any; greet: () => string; } ->firstName : string ->this.lastName : any ->this : { firstName: string; lastName: any; greet: () => string; } ->lastName : any - -}; - -var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); ->fred : { firstName: string; lastName: any; greet: () => string; } ->new Person({ firstName: "Fred", lastName: "Flintstone" }) : { firstName: string; lastName: any; greet: () => string; } ->Person : (firstNameOrPojo: any, lastName: any) => any ->{ firstName: "Fred", lastName: "Flintstone" } : { firstName: string; lastName: string; } ->firstName : string ->"Fred" : "Fred" ->lastName : string ->"Flintstone" : "Flintstone" - -console.log(fred.greet()); ->console.log(fred.greet()) : void ->console.log : (message?: any, ...optionalParams: any[]) => void ->console : Console ->log : (message?: any, ...optionalParams: any[]) => void ->fred.greet() : string ->fred.greet : () => string ->fred : { firstName: string; lastName: any; greet: () => string; } ->greet : () => string - diff --git a/tests/cases/compiler/jsConstructorFunction.ts b/tests/cases/compiler/jsConstructorFunction.ts deleted file mode 100644 index 2cb0d16b766..00000000000 --- a/tests/cases/compiler/jsConstructorFunction.ts +++ /dev/null @@ -1,22 +0,0 @@ -// @allowJs: true -// @checkJs: true -// @noEmit: true -// @filename: index.js -// @lib: es5, dom -var Person = function (firstNameOrPojo, lastName) { - - if (typeof firstNameOrPojo === "string") { - this.firstName = firstNameOrPojo; - this.lastName = lastName; - } else { - return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); - } -}; - -Person.prototype.greet = function greet() { - return `Hello, I am ${this.firstName} ${this.lastName}.`; -}; - -var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); - -console.log(fred.greet()); \ No newline at end of file diff --git a/tests/cases/conformance/salsa/constructorFunctions.ts b/tests/cases/conformance/salsa/constructorFunctions.ts new file mode 100644 index 00000000000..4f1a0368244 --- /dev/null +++ b/tests/cases/conformance/salsa/constructorFunctions.ts @@ -0,0 +1,36 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @filename: index.js + +function C1() { + if (!(this instanceof C1)) return new C1(); + this.x = 1; +} + +const c1_v1 = C1(); +const c1_v2 = new C1(); + +var C2 = function () { + if (!(this instanceof C2)) return new C2(); + this.x = 1; +}; + +const c2_v1 = C2(); +const c2_v2 = new C2(); + +/** @class */ +function C3() { + if (!(this instanceof C3)) return new C3(); +}; + +const c3_v1 = C3(); +const c3_v2 = new C3(); + +/** @class */ +var C4 = function () { + if (!(this instanceof C4)) return new C4(); +}; + +const c4_v1 = C4(); +const c4_v2 = new C4(); \ No newline at end of file