mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Report a semantic error for an arrow function with a "this" parameter.
Fixes #9744.
This commit is contained in:
@@ -21857,6 +21857,9 @@ namespace ts {
|
||||
if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) {
|
||||
error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter);
|
||||
}
|
||||
if (func.kind === SyntaxKind.ArrowFunction) {
|
||||
error(node, Diagnostics.An_arrow_function_cannot_have_a_this_parameter);
|
||||
}
|
||||
}
|
||||
|
||||
// Only check rest parameter type if it's not a binding pattern. Since binding patterns are
|
||||
|
||||
@@ -2417,6 +2417,10 @@
|
||||
"category": "Error",
|
||||
"code": 2729
|
||||
},
|
||||
"An arrow function cannot have a 'this' parameter.": {
|
||||
"category": "Error",
|
||||
"code": 2730
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -3537,8 +3537,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If we had "(" followed by something that's not an identifier,
|
||||
// then this definitely doesn't look like a lambda.
|
||||
if (!isIdentifier()) {
|
||||
// then this definitely doesn't look like a lambda. "this" is not
|
||||
// valid, but we want to parse it and then give a semantic error.
|
||||
if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) {
|
||||
return Tristate.False;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,12 +93,13 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(172,39): e
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(172,40): error TS1128: Declaration or statement expected.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(172,42): error TS2693: 'number' only refers to a type, but is being used as a value here.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(172,49): error TS1005: ';' expected.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(175,29): error TS2304: Cannot find name 'm'.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(175,32): error TS1005: ';' expected.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(175,35): error TS2304: Cannot find name 'm'.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(175,23): error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(176,16): error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(177,19): error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(178,22): error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts (64 errors) ====
|
||||
==== tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts (65 errors) ====
|
||||
class C {
|
||||
n: number;
|
||||
explicitThis(this: this, m: number): number {
|
||||
@@ -430,10 +431,15 @@ tests/cases/conformance/types/thisType/thisTypeInFunctionsNegative.ts(175,35): e
|
||||
|
||||
// can't name parameters 'this' in a lambda.
|
||||
c.explicitProperty = (this, m) => m + this.n;
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'm'.
|
||||
~~
|
||||
!!! error TS1005: ';' expected.
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'm'.
|
||||
~~~~
|
||||
!!! error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
const f2 = <T>(this: {n: number}, m: number) => m + this.n;
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
const f3 = async (this: {n: number}, m: number) => m + this.n;
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
const f4 = async <T>(this: {n: number}, m: number) => m + this.n;
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2730: An arrow function cannot have a 'this' parameter.
|
||||
|
||||
@@ -174,69 +174,60 @@ function initializer(this: C = new C()): number { return this.n; }
|
||||
|
||||
// can't name parameters 'this' in a lambda.
|
||||
c.explicitProperty = (this, m) => m + this.n;
|
||||
const f2 = <T>(this: {n: number}, m: number) => m + this.n;
|
||||
const f3 = async (this: {n: number}, m: number) => m + this.n;
|
||||
const f4 = async <T>(this: {n: number}, m: number) => m + this.n;
|
||||
|
||||
|
||||
//// [thisTypeInFunctionsNegative.js]
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
class C {
|
||||
explicitThis(m) {
|
||||
return this.n + m;
|
||||
}
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var _this = this;
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
implicitThis(m) {
|
||||
return this.n + m;
|
||||
}
|
||||
C.prototype.explicitThis = function (m) {
|
||||
explicitC(m) {
|
||||
return this.n + m;
|
||||
};
|
||||
C.prototype.implicitThis = function (m) {
|
||||
}
|
||||
explicitProperty(m) {
|
||||
return this.n + m;
|
||||
};
|
||||
C.prototype.explicitC = function (m) {
|
||||
return this.n + m;
|
||||
};
|
||||
C.prototype.explicitProperty = function (m) {
|
||||
return this.n + m;
|
||||
};
|
||||
C.prototype.explicitVoid = function (m) {
|
||||
}
|
||||
explicitVoid(m) {
|
||||
return this.n + m; // 'n' doesn't exist on type 'void'.
|
||||
};
|
||||
return C;
|
||||
}());
|
||||
var D = /** @class */ (function () {
|
||||
function D() {
|
||||
}
|
||||
D.prototype.explicitThis = function (m) {
|
||||
}
|
||||
class D {
|
||||
explicitThis(m) {
|
||||
return this.x + m;
|
||||
};
|
||||
D.prototype.explicitD = function (m) {
|
||||
}
|
||||
explicitD(m) {
|
||||
return this.x + m;
|
||||
};
|
||||
return D;
|
||||
}());
|
||||
var impl = {
|
||||
}
|
||||
}
|
||||
let impl = {
|
||||
a: 12,
|
||||
explicitVoid1: function () {
|
||||
explicitVoid1() {
|
||||
return this.a; // error, no 'a' in 'void'
|
||||
},
|
||||
explicitVoid2: function () { return _this.a; },
|
||||
explicitStructural: function () { return 12; },
|
||||
explicitInterface: function () { return 12; },
|
||||
explicitThis: function () {
|
||||
explicitVoid2: () => this.a,
|
||||
explicitStructural: () => 12,
|
||||
explicitInterface: () => 12,
|
||||
explicitThis() {
|
||||
return this.a;
|
||||
}
|
||||
},
|
||||
};
|
||||
var implExplicitStructural = impl.explicitStructural;
|
||||
let implExplicitStructural = impl.explicitStructural;
|
||||
implExplicitStructural(); // error, no 'a' in 'void'
|
||||
var implExplicitInterface = impl.explicitInterface;
|
||||
let implExplicitInterface = impl.explicitInterface;
|
||||
implExplicitInterface(); // error, no 'a' in 'void'
|
||||
function explicitStructural(x) {
|
||||
return x + this.y;
|
||||
@@ -247,15 +238,15 @@ function propertyName(x) {
|
||||
function voidThisSpecified(x) {
|
||||
return x + this.notSpecified;
|
||||
}
|
||||
var ok = { y: 12, explicitStructural: explicitStructural };
|
||||
var wrongPropertyType = { y: 'foo', explicitStructural: explicitStructural };
|
||||
var wrongPropertyName = { wrongName: 12, explicitStructural: explicitStructural };
|
||||
let ok = { y: 12, explicitStructural };
|
||||
let wrongPropertyType = { y: 'foo', explicitStructural };
|
||||
let wrongPropertyName = { wrongName: 12, explicitStructural };
|
||||
ok.f(); // not enough arguments
|
||||
ok.f('wrong type');
|
||||
ok.f(13, 'too many arguments');
|
||||
wrongPropertyType.f(13);
|
||||
wrongPropertyName.f(13);
|
||||
var c = new C();
|
||||
let c = new C();
|
||||
c.explicitC(); // not enough arguments
|
||||
c.explicitC('wrong type');
|
||||
c.explicitC(13, 'too many arguments');
|
||||
@@ -269,8 +260,8 @@ c.explicitProperty(); // not enough arguments
|
||||
c.explicitProperty('wrong type 3');
|
||||
c.explicitProperty(15, 'too many arguments 3');
|
||||
// oops, this triggers contextual typing, which needs to be updated to understand that =>'s `this` is void.
|
||||
var specifiedToVoid = explicitStructural;
|
||||
var reconstructed = {
|
||||
let specifiedToVoid = explicitStructural;
|
||||
let reconstructed = {
|
||||
n: 12,
|
||||
explicitThis: c.explicitThis,
|
||||
explicitC: c.explicitC,
|
||||
@@ -279,8 +270,8 @@ var reconstructed = {
|
||||
};
|
||||
;
|
||||
// lambdas have this: void for assignability purposes (and this unbound (free) for body checking)
|
||||
var d = new D();
|
||||
var explicitXProperty;
|
||||
let d = new D();
|
||||
let explicitXProperty;
|
||||
// from differing object types
|
||||
c.explicitC = function (m) { return this.x + m; };
|
||||
c.explicitProperty = explicitXProperty;
|
||||
@@ -293,64 +284,41 @@ c.explicitThis = d.explicitThis;
|
||||
c.explicitVoid = d.explicitD;
|
||||
c.explicitVoid = d.explicitThis;
|
||||
/// class-based polymorphic assignability (with inheritance!) ///
|
||||
var Base1 = /** @class */ (function () {
|
||||
function Base1() {
|
||||
}
|
||||
Base1.prototype.polymorphic = function () { return this.x; };
|
||||
Base1.prototype.explicit = function () { return this.x; };
|
||||
Base1.explicitStatic = function () { return this.x; };
|
||||
return Base1;
|
||||
}());
|
||||
var Derived1 = /** @class */ (function (_super) {
|
||||
__extends(Derived1, _super);
|
||||
function Derived1() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return Derived1;
|
||||
}(Base1));
|
||||
var Base2 = /** @class */ (function () {
|
||||
function Base2() {
|
||||
}
|
||||
Base2.prototype.polymorphic = function () { return this.y; };
|
||||
Base2.prototype.explicit = function () { return this.x; };
|
||||
return Base2;
|
||||
}());
|
||||
var Derived2 = /** @class */ (function (_super) {
|
||||
__extends(Derived2, _super);
|
||||
function Derived2() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return Derived2;
|
||||
}(Base2));
|
||||
var b1 = new Base1();
|
||||
var d1 = new Derived1();
|
||||
var b2 = new Base2();
|
||||
var d2 = new Derived2();
|
||||
class Base1 {
|
||||
polymorphic() { return this.x; }
|
||||
explicit() { return this.x; }
|
||||
static explicitStatic() { return this.x; }
|
||||
}
|
||||
class Derived1 extends Base1 {
|
||||
}
|
||||
class Base2 {
|
||||
polymorphic() { return this.y; }
|
||||
explicit() { return this.x; }
|
||||
}
|
||||
class Derived2 extends Base2 {
|
||||
}
|
||||
let b1 = new Base1();
|
||||
let d1 = new Derived1();
|
||||
let b2 = new Base2();
|
||||
let d2 = new Derived2();
|
||||
b1.polymorphic = b2.polymorphic; // error, 'this.y' not in Base1: { x }
|
||||
b1.explicit = b2.polymorphic; // error, 'y' not in Base1: { x }
|
||||
d1.explicit = b2.polymorphic; // error, 'y' not in Base1: { x }
|
||||
////// use this-type for construction with new ////
|
||||
function VoidThis() {
|
||||
}
|
||||
var voidThis = new VoidThis();
|
||||
let voidThis = new VoidThis();
|
||||
///// syntax-ish errors /////
|
||||
var ThisConstructor = /** @class */ (function () {
|
||||
function ThisConstructor(n) {
|
||||
class ThisConstructor {
|
||||
constructor(n) {
|
||||
this.n = n;
|
||||
}
|
||||
return ThisConstructor;
|
||||
}());
|
||||
}
|
||||
var thisConstructorType;
|
||||
function notFirst(a) { return this.n; }
|
||||
///// parse errors /////
|
||||
function modifiers() { return this.n; }
|
||||
function restParam() {
|
||||
var = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
[_i] = arguments[_i];
|
||||
}
|
||||
return this.n;
|
||||
}
|
||||
function restParam(...) { return this.n; }
|
||||
function optional() { return this.n; }
|
||||
function decorated() { return this.n; }
|
||||
function initializer(, C) { }
|
||||
@@ -360,5 +328,7 @@ number;
|
||||
return this.n;
|
||||
}
|
||||
// can't name parameters 'this' in a lambda.
|
||||
c.explicitProperty = (this, m);
|
||||
m + this.n;
|
||||
c.explicitProperty = (m) => m + this.n;
|
||||
const f2 = (m) => m + this.n;
|
||||
const f3 = (m) => __awaiter(this, void 0, void 0, function* () { return m + this.n; });
|
||||
const f4 = (m) => __awaiter(this, void 0, void 0, function* () { return m + this.n; });
|
||||
|
||||
@@ -661,4 +661,30 @@ c.explicitProperty = (this, m) => m + this.n;
|
||||
>c.explicitProperty : Symbol(C.explicitProperty, Decl(thisTypeInFunctionsNegative.ts, 10, 5))
|
||||
>c : Symbol(c, Decl(thisTypeInFunctionsNegative.ts, 70, 3))
|
||||
>explicitProperty : Symbol(C.explicitProperty, Decl(thisTypeInFunctionsNegative.ts, 10, 5))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctionsNegative.ts, 174, 22))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 174, 27))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 174, 27))
|
||||
|
||||
const f2 = <T>(this: {n: number}, m: number) => m + this.n;
|
||||
>f2 : Symbol(f2, Decl(thisTypeInFunctionsNegative.ts, 175, 5))
|
||||
>T : Symbol(T, Decl(thisTypeInFunctionsNegative.ts, 175, 12))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctionsNegative.ts, 175, 15))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctionsNegative.ts, 175, 22))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 175, 33))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 175, 33))
|
||||
|
||||
const f3 = async (this: {n: number}, m: number) => m + this.n;
|
||||
>f3 : Symbol(f3, Decl(thisTypeInFunctionsNegative.ts, 176, 5))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctionsNegative.ts, 176, 18))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctionsNegative.ts, 176, 25))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 176, 36))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 176, 36))
|
||||
|
||||
const f4 = async <T>(this: {n: number}, m: number) => m + this.n;
|
||||
>f4 : Symbol(f4, Decl(thisTypeInFunctionsNegative.ts, 177, 5))
|
||||
>T : Symbol(T, Decl(thisTypeInFunctionsNegative.ts, 177, 18))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctionsNegative.ts, 177, 21))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctionsNegative.ts, 177, 28))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 177, 39))
|
||||
>m : Symbol(m, Decl(thisTypeInFunctionsNegative.ts, 177, 39))
|
||||
|
||||
|
||||
@@ -777,16 +777,53 @@ function initializer(this: C = new C()): number { return this.n; }
|
||||
|
||||
// can't name parameters 'this' in a lambda.
|
||||
c.explicitProperty = (this, m) => m + this.n;
|
||||
>c.explicitProperty = (this, m) : any
|
||||
>c.explicitProperty = (this, m) => m + this.n : (this: { n: number; }, m: number) => any
|
||||
>c.explicitProperty : (this: { n: number; }, m: number) => number
|
||||
>c : C
|
||||
>explicitProperty : (this: { n: number; }, m: number) => number
|
||||
>(this, m) : any
|
||||
>this, m : any
|
||||
>this : any
|
||||
>m : any
|
||||
>(this, m) => m + this.n : (this: { n: number; }, m: number) => any
|
||||
>this : { n: number; }
|
||||
>m : number
|
||||
>m + this.n : any
|
||||
>m : any
|
||||
>m : number
|
||||
>this.n : any
|
||||
>this : any
|
||||
>n : any
|
||||
|
||||
const f2 = <T>(this: {n: number}, m: number) => m + this.n;
|
||||
>f2 : <T>(this: { n: number; }, m: number) => any
|
||||
><T>(this: {n: number}, m: number) => m + this.n : <T>(this: { n: number; }, m: number) => any
|
||||
>T : T
|
||||
>this : { n: number; }
|
||||
>n : number
|
||||
>m : number
|
||||
>m + this.n : any
|
||||
>m : number
|
||||
>this.n : any
|
||||
>this : any
|
||||
>n : any
|
||||
|
||||
const f3 = async (this: {n: number}, m: number) => m + this.n;
|
||||
>f3 : (this: { n: number; }, m: number) => Promise<any>
|
||||
>async (this: {n: number}, m: number) => m + this.n : (this: { n: number; }, m: number) => Promise<any>
|
||||
>this : { n: number; }
|
||||
>n : number
|
||||
>m : number
|
||||
>m + this.n : any
|
||||
>m : number
|
||||
>this.n : any
|
||||
>this : any
|
||||
>n : any
|
||||
|
||||
const f4 = async <T>(this: {n: number}, m: number) => m + this.n;
|
||||
>f4 : <T>(this: { n: number; }, m: number) => Promise<any>
|
||||
>async <T>(this: {n: number}, m: number) => m + this.n : <T>(this: { n: number; }, m: number) => Promise<any>
|
||||
>T : T
|
||||
>this : { n: number; }
|
||||
>n : number
|
||||
>m : number
|
||||
>m + this.n : any
|
||||
>m : number
|
||||
>this.n : any
|
||||
>this : any
|
||||
>n : any
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// @target: es6
|
||||
|
||||
class C {
|
||||
n: number;
|
||||
explicitThis(this: this, m: number): number {
|
||||
@@ -173,3 +175,6 @@ function initializer(this: C = new C()): number { return this.n; }
|
||||
|
||||
// can't name parameters 'this' in a lambda.
|
||||
c.explicitProperty = (this, m) => m + this.n;
|
||||
const f2 = <T>(this: {n: number}, m: number) => m + this.n;
|
||||
const f3 = async (this: {n: number}, m: number) => m + this.n;
|
||||
const f4 = async <T>(this: {n: number}, m: number) => m + this.n;
|
||||
|
||||
Reference in New Issue
Block a user