Error on this.xxx access of previously declared but uninitialized property (#38030)
* Error on this.xxx access of previously declared but uninitialized property * Add tests * Accept new baselines
This commit is contained in:
parent
9d8a70c809
commit
16d2eb7075
|
@ -1364,7 +1364,7 @@ namespace ts {
|
||||||
return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile);
|
return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaration.pos <= usage.pos) {
|
if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) {
|
||||||
// declaration is before usage
|
// declaration is before usage
|
||||||
if (declaration.kind === SyntaxKind.BindingElement) {
|
if (declaration.kind === SyntaxKind.BindingElement) {
|
||||||
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
|
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])
|
||||||
|
|
|
@ -2,10 +2,11 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstr
|
||||||
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||||
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
|
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||||
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||||
|
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2729: Property 'prop' is used before its initialization.
|
||||||
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||||
|
|
||||||
|
|
||||||
==== tests/cases/compiler/abstractPropertyInConstructor.ts (5 errors) ====
|
==== tests/cases/compiler/abstractPropertyInConstructor.ts (6 errors) ====
|
||||||
abstract class AbstractClass {
|
abstract class AbstractClass {
|
||||||
constructor(str: string, other: AbstractClass) {
|
constructor(str: string, other: AbstractClass) {
|
||||||
this.method(parseInt(str));
|
this.method(parseInt(str));
|
||||||
|
@ -39,6 +40,9 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abst
|
||||||
other = this.prop;
|
other = this.prop;
|
||||||
~~~~
|
~~~~
|
||||||
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
|
||||||
|
~~~~
|
||||||
|
!!! error TS2729: Property 'prop' is used before its initialization.
|
||||||
|
!!! related TS2728 tests/cases/compiler/abstractPropertyInConstructor.ts:20:14: 'prop' is declared here.
|
||||||
fn = () => this.prop;
|
fn = () => this.prop;
|
||||||
|
|
||||||
method2() {
|
method2() {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
tests/cases/compiler/initializerWithThisPropertyAccess.ts(3,14): error TS2729: Property 'a' is used before its initialization.
|
||||||
|
tests/cases/compiler/initializerWithThisPropertyAccess.ts(24,29): error TS2729: Property 'bar' is used before its initialization.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/initializerWithThisPropertyAccess.ts (2 errors) ====
|
||||||
|
class A {
|
||||||
|
a: number;
|
||||||
|
b = this.a; // Error
|
||||||
|
~
|
||||||
|
!!! error TS2729: Property 'a' is used before its initialization.
|
||||||
|
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:2:5: 'a' is declared here.
|
||||||
|
c = () => this.a;
|
||||||
|
d = (new A()).a;
|
||||||
|
constructor() {
|
||||||
|
this.a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
x = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
a!: number;
|
||||||
|
b = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repro from #37979
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
private bar: Bar;
|
||||||
|
readonly barProp = this.bar.prop;
|
||||||
|
~~~
|
||||||
|
!!! error TS2729: Property 'bar' is used before its initialization.
|
||||||
|
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:23:13: 'bar' is declared here.
|
||||||
|
constructor() {
|
||||||
|
this.bar = new Bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
readonly prop = false;
|
||||||
|
}
|
||||||
|
|
114
tests/baselines/reference/initializerWithThisPropertyAccess.js
Normal file
114
tests/baselines/reference/initializerWithThisPropertyAccess.js
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
//// [initializerWithThisPropertyAccess.ts]
|
||||||
|
class A {
|
||||||
|
a: number;
|
||||||
|
b = this.a; // Error
|
||||||
|
c = () => this.a;
|
||||||
|
d = (new A()).a;
|
||||||
|
constructor() {
|
||||||
|
this.a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
x = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
a!: number;
|
||||||
|
b = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repro from #37979
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
private bar: Bar;
|
||||||
|
readonly barProp = this.bar.prop;
|
||||||
|
constructor() {
|
||||||
|
this.bar = new Bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
readonly prop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// [initializerWithThisPropertyAccess.js]
|
||||||
|
"use strict";
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
return function (d, b) {
|
||||||
|
extendStatics(d, b);
|
||||||
|
function __() { this.constructor = d; }
|
||||||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var A = /** @class */ (function () {
|
||||||
|
function A() {
|
||||||
|
var _this = this;
|
||||||
|
this.b = this.a; // Error
|
||||||
|
this.c = function () { return _this.a; };
|
||||||
|
this.d = (new A()).a;
|
||||||
|
this.a = 1;
|
||||||
|
}
|
||||||
|
return A;
|
||||||
|
}());
|
||||||
|
var B = /** @class */ (function (_super) {
|
||||||
|
__extends(B, _super);
|
||||||
|
function B() {
|
||||||
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
||||||
|
_this.x = _this.a;
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
return B;
|
||||||
|
}(A));
|
||||||
|
var C = /** @class */ (function () {
|
||||||
|
function C() {
|
||||||
|
this.b = this.a;
|
||||||
|
}
|
||||||
|
return C;
|
||||||
|
}());
|
||||||
|
// Repro from #37979
|
||||||
|
var Foo = /** @class */ (function () {
|
||||||
|
function Foo() {
|
||||||
|
this.barProp = this.bar.prop;
|
||||||
|
this.bar = new Bar();
|
||||||
|
}
|
||||||
|
return Foo;
|
||||||
|
}());
|
||||||
|
var Bar = /** @class */ (function () {
|
||||||
|
function Bar() {
|
||||||
|
this.prop = false;
|
||||||
|
}
|
||||||
|
return Bar;
|
||||||
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
//// [initializerWithThisPropertyAccess.d.ts]
|
||||||
|
declare class A {
|
||||||
|
a: number;
|
||||||
|
b: number;
|
||||||
|
c: () => number;
|
||||||
|
d: number;
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
declare class B extends A {
|
||||||
|
x: number;
|
||||||
|
}
|
||||||
|
declare class C {
|
||||||
|
a: number;
|
||||||
|
b: number;
|
||||||
|
}
|
||||||
|
declare class Foo {
|
||||||
|
private bar;
|
||||||
|
readonly barProp = false;
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
declare class Bar {
|
||||||
|
readonly prop = false;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
|
||||||
|
class A {
|
||||||
|
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
|
||||||
|
a: number;
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
|
||||||
|
b = this.a; // Error
|
||||||
|
>b : Symbol(A.b, Decl(initializerWithThisPropertyAccess.ts, 1, 14))
|
||||||
|
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
|
||||||
|
c = () => this.a;
|
||||||
|
>c : Symbol(A.c, Decl(initializerWithThisPropertyAccess.ts, 2, 15))
|
||||||
|
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
|
||||||
|
d = (new A()).a;
|
||||||
|
>d : Symbol(A.d, Decl(initializerWithThisPropertyAccess.ts, 3, 21))
|
||||||
|
>(new A()).a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.a = 1;
|
||||||
|
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
>B : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
|
||||||
|
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
|
||||||
|
|
||||||
|
x = this.a;
|
||||||
|
>x : Symbol(B.x, Decl(initializerWithThisPropertyAccess.ts, 10, 19))
|
||||||
|
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
>this : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
|
||||||
|
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
>C : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
|
||||||
|
|
||||||
|
a!: number;
|
||||||
|
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||||
|
|
||||||
|
b = this.a;
|
||||||
|
>b : Symbol(C.b, Decl(initializerWithThisPropertyAccess.ts, 15, 15))
|
||||||
|
>this.a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||||
|
>this : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
|
||||||
|
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repro from #37979
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
>Foo : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||||
|
|
||||||
|
private bar: Bar;
|
||||||
|
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||||
|
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||||
|
|
||||||
|
readonly barProp = this.bar.prop;
|
||||||
|
>barProp : Symbol(Foo.barProp, Decl(initializerWithThisPropertyAccess.ts, 22, 21))
|
||||||
|
>this.bar.prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||||
|
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||||
|
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||||
|
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||||
|
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.bar = new Bar();
|
||||||
|
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||||
|
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
|
||||||
|
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
|
||||||
|
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
|
||||||
|
|
||||||
|
readonly prop = false;
|
||||||
|
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
|
||||||
|
class A {
|
||||||
|
>A : A
|
||||||
|
|
||||||
|
a: number;
|
||||||
|
>a : number
|
||||||
|
|
||||||
|
b = this.a; // Error
|
||||||
|
>b : number
|
||||||
|
>this.a : number
|
||||||
|
>this : this
|
||||||
|
>a : number
|
||||||
|
|
||||||
|
c = () => this.a;
|
||||||
|
>c : () => number
|
||||||
|
>() => this.a : () => number
|
||||||
|
>this.a : number
|
||||||
|
>this : this
|
||||||
|
>a : number
|
||||||
|
|
||||||
|
d = (new A()).a;
|
||||||
|
>d : number
|
||||||
|
>(new A()).a : number
|
||||||
|
>(new A()) : A
|
||||||
|
>new A() : A
|
||||||
|
>A : typeof A
|
||||||
|
>a : number
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.a = 1;
|
||||||
|
>this.a = 1 : 1
|
||||||
|
>this.a : number
|
||||||
|
>this : this
|
||||||
|
>a : number
|
||||||
|
>1 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
>B : B
|
||||||
|
>A : A
|
||||||
|
|
||||||
|
x = this.a;
|
||||||
|
>x : number
|
||||||
|
>this.a : number
|
||||||
|
>this : this
|
||||||
|
>a : number
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
>C : C
|
||||||
|
|
||||||
|
a!: number;
|
||||||
|
>a : number
|
||||||
|
|
||||||
|
b = this.a;
|
||||||
|
>b : number
|
||||||
|
>this.a : number
|
||||||
|
>this : this
|
||||||
|
>a : number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repro from #37979
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
>Foo : Foo
|
||||||
|
|
||||||
|
private bar: Bar;
|
||||||
|
>bar : Bar
|
||||||
|
|
||||||
|
readonly barProp = this.bar.prop;
|
||||||
|
>barProp : false
|
||||||
|
>this.bar.prop : false
|
||||||
|
>this.bar : Bar
|
||||||
|
>this : this
|
||||||
|
>bar : Bar
|
||||||
|
>prop : false
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.bar = new Bar();
|
||||||
|
>this.bar = new Bar() : Bar
|
||||||
|
>this.bar : Bar
|
||||||
|
>this : this
|
||||||
|
>bar : Bar
|
||||||
|
>new Bar() : Bar
|
||||||
|
>Bar : typeof Bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
>Bar : Bar
|
||||||
|
|
||||||
|
readonly prop = false;
|
||||||
|
>prop : false
|
||||||
|
>false : false
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts(24,14): error TS2729: Property 's' is used before its initialization.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts (1 errors) ====
|
||||||
|
// EveryType used in a nested scope of a different EveryType with the same name, type of the identifier is the one defined in the inner scope
|
||||||
|
|
||||||
|
var s: string;
|
||||||
|
module M1 {
|
||||||
|
export var s: number;
|
||||||
|
var n = s;
|
||||||
|
var n: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
module M2 {
|
||||||
|
var s: number;
|
||||||
|
var n = s;
|
||||||
|
var n: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fn() {
|
||||||
|
var s: boolean;
|
||||||
|
var n = s;
|
||||||
|
var n: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
s: Date;
|
||||||
|
n = this.s;
|
||||||
|
~
|
||||||
|
!!! error TS2729: Property 's' is used before its initialization.
|
||||||
|
!!! related TS2728 tests/cases/conformance/expressions/identifiers/scopeResolutionIdentifiers.ts:23:5: 's' is declared here.
|
||||||
|
x() {
|
||||||
|
var p = this.n;
|
||||||
|
var p: Date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module M3 {
|
||||||
|
var s: any;
|
||||||
|
module M4 {
|
||||||
|
var n = s;
|
||||||
|
var n: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
tests/cases/compiler/initializerWithThisPropertyAccess.ts
Normal file
35
tests/cases/compiler/initializerWithThisPropertyAccess.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// @strict: true
|
||||||
|
// @declaration: true
|
||||||
|
|
||||||
|
class A {
|
||||||
|
a: number;
|
||||||
|
b = this.a; // Error
|
||||||
|
c = () => this.a;
|
||||||
|
d = (new A()).a;
|
||||||
|
constructor() {
|
||||||
|
this.a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
x = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
a!: number;
|
||||||
|
b = this.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repro from #37979
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
private bar: Bar;
|
||||||
|
readonly barProp = this.bar.prop;
|
||||||
|
constructor() {
|
||||||
|
this.bar = new Bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
readonly prop = false;
|
||||||
|
}
|
Loading…
Reference in a new issue