Skip to content

Commit 0485bb6

Browse files
Merge pull request microsoft#10506 from Microsoft/ctorTag
Issue error when tagging templates and decorating with only-constructable entities
2 parents 598ca48 + 5ce285c commit 0485bb6

20 files changed

+244
-12
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11960,18 +11960,12 @@ namespace ts {
1196011960
// Function interface, since they have none by default. This is a bit of a leap of faith
1196111961
// that the user will not add any.
1196211962
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
11963-
1196411963
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
11965-
// TS 1.0 spec: 4.12
11966-
// If FuncExpr is of type Any, or of an object type that has no call or construct signatures
11967-
// but is a subtype of the Function interface, the call is an untyped function call. In an
11968-
// untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
11964+
11965+
// TS 1.0 Spec: 4.12
11966+
// In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
1196911967
// types are provided for the argument expressions, and the result is always of type Any.
11970-
// We exclude union types because we may have a union of function types that happen to have
11971-
// no common signatures.
11972-
if (isTypeAny(funcType) ||
11973-
(isTypeAny(apparentType) && funcType.flags & TypeFlags.TypeParameter) ||
11974-
(!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
11968+
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
1197511969
// The unknownType indicates that an error already occurred (and was reported). No
1197611970
// need to report another error in this case.
1197711971
if (funcType !== unknownType && node.typeArguments) {
@@ -11994,6 +11988,29 @@ namespace ts {
1199411988
return resolveCall(node, callSignatures, candidatesOutArray);
1199511989
}
1199611990

11991+
/**
11992+
* TS 1.0 spec: 4.12
11993+
* If FuncExpr is of type Any, or of an object type that has no call or construct signatures
11994+
* but is a subtype of the Function interface, the call is an untyped function call.
11995+
*/
11996+
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number) {
11997+
if (isTypeAny(funcType)) {
11998+
return true;
11999+
}
12000+
if (isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter) {
12001+
return true;
12002+
}
12003+
if (!numCallSignatures && !numConstructSignatures) {
12004+
// We exclude union types because we may have a union of function types that happen to have
12005+
// no common signatures.
12006+
if (funcType.flags & TypeFlags.Union) {
12007+
return false;
12008+
}
12009+
return isTypeAssignableTo(funcType, globalFunctionType);
12010+
}
12011+
return false;
12012+
}
12013+
1199712014
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
1199812015
if (node.arguments && languageVersion < ScriptTarget.ES5) {
1199912016
const spreadIndex = getSpreadArgumentIndex(node.arguments);
@@ -12119,8 +12136,9 @@ namespace ts {
1211912136
}
1212012137

1212112138
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
12139+
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
1212212140

12123-
if (isTypeAny(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) {
12141+
if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, constructSignatures.length)) {
1212412142
return resolveUntypedCall(node);
1212512143
}
1212612144

@@ -12165,7 +12183,8 @@ namespace ts {
1216512183
}
1216612184

1216712185
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
12168-
if (funcType === anyType || (!callSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
12186+
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
12187+
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
1216912188
return resolveUntypedCall(node);
1217012189
}
1217112190

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/conformance/decorators/class/constructableDecoratorOnClass01.ts(4,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
2+
Cannot invoke an expression whose type lacks a call signature.
3+
4+
5+
==== tests/cases/conformance/decorators/class/constructableDecoratorOnClass01.ts (1 errors) ====
6+
7+
class CtorDtor {}
8+
9+
@CtorDtor
10+
~~~~~~~~~
11+
!!! error TS1238: Unable to resolve signature of class decorator when called as an expression.
12+
!!! error TS1238: Cannot invoke an expression whose type lacks a call signature.
13+
class C {
14+
15+
}
16+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [constructableDecoratorOnClass01.ts]
2+
3+
class CtorDtor {}
4+
5+
@CtorDtor
6+
class C {
7+
8+
}
9+
10+
11+
//// [constructableDecoratorOnClass01.js]
12+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
13+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
15+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
16+
return c > 3 && r && Object.defineProperty(target, key, r), r;
17+
};
18+
var CtorDtor = (function () {
19+
function CtorDtor() {
20+
}
21+
return CtorDtor;
22+
}());
23+
var C = (function () {
24+
function C() {
25+
}
26+
C = __decorate([
27+
CtorDtor
28+
], C);
29+
return C;
30+
}());
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/decorators/class/constructableDecoratorOnClass01.ts ===
2+
3+
class CtorDtor {}
4+
>CtorDtor : Symbol(CtorDtor, Decl(constructableDecoratorOnClass01.ts, 0, 0))
5+
6+
@CtorDtor
7+
>CtorDtor : Symbol(CtorDtor, Decl(constructableDecoratorOnClass01.ts, 0, 0))
8+
9+
class C {
10+
>C : Symbol(C, Decl(constructableDecoratorOnClass01.ts, 1, 17))
11+
12+
}
13+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/decorators/class/constructableDecoratorOnClass01.ts ===
2+
3+
class CtorDtor {}
4+
>CtorDtor : CtorDtor
5+
6+
@CtorDtor
7+
>CtorDtor : typeof CtorDtor
8+
9+
class C {
10+
>C : C
11+
12+
}
13+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [taggedTemplateUntypedTagCall01.ts]
2+
var tag: Function;
3+
tag `Hello world!`;
4+
5+
//// [taggedTemplateUntypedTagCall01.js]
6+
var tag;
7+
(_a = ["Hello world!"], _a.raw = ["Hello world!"], tag(_a));
8+
var _a;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateUntypedTagCall01.ts ===
2+
var tag: Function;
3+
>tag : Symbol(tag, Decl(taggedTemplateUntypedTagCall01.ts, 0, 3))
4+
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
5+
6+
tag `Hello world!`;
7+
>tag : Symbol(tag, Decl(taggedTemplateUntypedTagCall01.ts, 0, 3))
8+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateUntypedTagCall01.ts ===
2+
var tag: Function;
3+
>tag : Function
4+
>Function : Function
5+
6+
tag `Hello world!`;
7+
>tag `Hello world!` : any
8+
>tag : Function
9+
>`Hello world!` : string
10+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag01.ts(3,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
2+
3+
4+
==== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag01.ts (1 errors) ====
5+
class CtorTag { }
6+
7+
CtorTag `Hello world!`;
8+
~~~~~~~~~~~~~~~~~~~~~~
9+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [taggedTemplateWithConstructableTag01.ts]
2+
class CtorTag { }
3+
4+
CtorTag `Hello world!`;
5+
6+
//// [taggedTemplateWithConstructableTag01.js]
7+
var CtorTag = (function () {
8+
function CtorTag() {
9+
}
10+
return CtorTag;
11+
}());
12+
(_a = ["Hello world!"], _a.raw = ["Hello world!"], CtorTag(_a));
13+
var _a;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag01.ts ===
2+
class CtorTag { }
3+
>CtorTag : Symbol(CtorTag, Decl(taggedTemplateWithConstructableTag01.ts, 0, 0))
4+
5+
CtorTag `Hello world!`;
6+
>CtorTag : Symbol(CtorTag, Decl(taggedTemplateWithConstructableTag01.ts, 0, 0))
7+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag01.ts ===
2+
class CtorTag { }
3+
>CtorTag : CtorTag
4+
5+
CtorTag `Hello world!`;
6+
>CtorTag `Hello world!` : any
7+
>CtorTag : typeof CtorTag
8+
>`Hello world!` : string
9+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag02.ts(6,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
2+
3+
4+
==== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag02.ts (1 errors) ====
5+
interface I {
6+
new (...args: any[]): string;
7+
new (): number;
8+
}
9+
var tag: I;
10+
tag `Hello world!`;
11+
~~~~~~~~~~~~~~~~~~
12+
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [taggedTemplateWithConstructableTag02.ts]
2+
interface I {
3+
new (...args: any[]): string;
4+
new (): number;
5+
}
6+
var tag: I;
7+
tag `Hello world!`;
8+
9+
//// [taggedTemplateWithConstructableTag02.js]
10+
var tag;
11+
(_a = ["Hello world!"], _a.raw = ["Hello world!"], tag(_a));
12+
var _a;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag02.ts ===
2+
interface I {
3+
>I : Symbol(I, Decl(taggedTemplateWithConstructableTag02.ts, 0, 0))
4+
5+
new (...args: any[]): string;
6+
>args : Symbol(args, Decl(taggedTemplateWithConstructableTag02.ts, 1, 9))
7+
8+
new (): number;
9+
}
10+
var tag: I;
11+
>tag : Symbol(tag, Decl(taggedTemplateWithConstructableTag02.ts, 4, 3))
12+
>I : Symbol(I, Decl(taggedTemplateWithConstructableTag02.ts, 0, 0))
13+
14+
tag `Hello world!`;
15+
>tag : Symbol(tag, Decl(taggedTemplateWithConstructableTag02.ts, 4, 3))
16+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/es6/templates/taggedTemplateWithConstructableTag02.ts ===
2+
interface I {
3+
>I : I
4+
5+
new (...args: any[]): string;
6+
>args : any[]
7+
8+
new (): number;
9+
}
10+
var tag: I;
11+
>tag : I
12+
>I : I
13+
14+
tag `Hello world!`;
15+
>tag `Hello world!` : any
16+
>tag : I
17+
>`Hello world!` : string
18+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @experimentalDecorators: true
2+
3+
class CtorDtor {}
4+
5+
@CtorDtor
6+
class C {
7+
8+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var tag: Function;
2+
tag `Hello world!`;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class CtorTag { }
2+
3+
CtorTag `Hello world!`;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface I {
2+
new (...args: any[]): string;
3+
new (): number;
4+
}
5+
var tag: I;
6+
tag `Hello world!`;

0 commit comments

Comments
 (0)