Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41896,6 +41896,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function checkParameterPropertySelfReference(parameter: ParameterDeclaration, initializer: Expression) {
if (!isIdentifier(parameter.name)) return;
const parameterName = parameter.name.escapedText;

function visitNode(node: Node): void {
if (isIdentifier(node) && node.escapedText === parameterName) {
// Ignore occurrences like `this.f` (property access name), which are not self-references
if (isPropertyAccessExpression(node.parent) && node.parent.name === node) {
// skip
}
else {
error(node, Diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(parameter.name));
return;
}
}
forEachChild(node, visitNode);
}

visitNode(initializer);
}

function checkParameter(node: ParameterDeclaration) {
// Grammar checking
// It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the
Expand All @@ -41904,6 +41925,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
checkGrammarModifiers(node);

checkVariableLikeDeclaration(node);

// Check for parameter property self-reference in initializer
if (node.initializer && isIdentifier(node.name) && hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) {
checkParameterPropertySelfReference(node, node.initializer);
}

const func = getContainingFunction(node)!;
if (hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) {
if (compilerOptions.erasableSyntaxOnly) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
parameterPropertySelfReference.ts(5,37): error TS2372: Parameter 'f' cannot reference itself.
parameterPropertySelfReference.ts(10,17): error TS2502: 'f' is referenced directly or indirectly in its own type annotation.
parameterPropertySelfReference.ts(10,39): error TS2372: Parameter 'f' cannot reference itself.
parameterPropertySelfReference.ts(15,36): error TS2372: Parameter 'g' cannot reference itself.
parameterPropertySelfReference.ts(20,39): error TS2372: Parameter 'h' cannot reference itself.
parameterPropertySelfReference.ts(25,29): error TS2372: Parameter 'x' cannot reference itself.
parameterPropertySelfReference.ts(28,34): error TS2372: Parameter 'param' cannot reference itself.
parameterPropertySelfReference.ts(30,32): error TS2372: Parameter 'param' cannot reference itself.


==== parameterPropertySelfReference.ts (8 errors) ====
// These should all produce "Parameter 'x' cannot reference itself" error (TS2372)

class TestParameterProperty {
// Parameter property with self-reference - currently NOT detected (BUG)
constructor(private f: number = f) {} // Should error: Parameter 'f' cannot reference itself
~
!!! error TS2372: Parameter 'f' cannot reference itself.
}

class TestParameterPropertyWithTypeof {
// Parameter property with typeof self-reference - from issue #62414
constructor(private f: typeof f = f) {} // Should error: Parameter 'f' cannot reference itself
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2502: 'f' is referenced directly or indirectly in its own type annotation.
~
!!! error TS2372: Parameter 'f' cannot reference itself.
}

class TestParameterPropertyPublic {
// Public parameter property
constructor(public g: string = g) {} // Should error: Parameter 'g' cannot reference itself
~
!!! error TS2372: Parameter 'g' cannot reference itself.
}

class TestParameterPropertyReadonly {
// Readonly parameter property
constructor(readonly h: boolean = h) {} // Should error: Parameter 'h' cannot reference itself
~
!!! error TS2372: Parameter 'h' cannot reference itself.
}

// These should work correctly (already implemented)
class TestRegularParameter {
constructor(x: number = x) {} // Should error: Parameter 'x' cannot reference itself (already works)
~
!!! error TS2372: Parameter 'x' cannot reference itself.
}

function regularFunction(param = param) {} // Should error: Parameter 'param' cannot reference itself (already works)
~~~~~
!!! error TS2372: Parameter 'param' cannot reference itself.

const arrowFunction = (param = param) => {}; // Should error: Parameter 'param' cannot reference itself (already works)
~~~~~
!!! error TS2372: Parameter 'param' cannot reference itself.

35 changes: 35 additions & 0 deletions tests/cases/compiler/parameterPropertySelfReference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @strict: true
// @noEmit: true
// @noTypesAndSymbols: true
// @noImplicitAny: false

// These should all produce "Parameter 'x' cannot reference itself" error (TS2372)

class TestParameterProperty {
// Parameter property with self-reference - currently NOT detected (BUG)
constructor(private f: number = f) {} // Should error: Parameter 'f' cannot reference itself
}

class TestParameterPropertyWithTypeof {
// Parameter property with typeof self-reference - from issue #62414
constructor(private f: typeof f = f) {} // Should error: Parameter 'f' cannot reference itself
}

class TestParameterPropertyPublic {
// Public parameter property
constructor(public g: string = g) {} // Should error: Parameter 'g' cannot reference itself
}

class TestParameterPropertyReadonly {
// Readonly parameter property
constructor(readonly h: boolean = h) {} // Should error: Parameter 'h' cannot reference itself
}

// These should work correctly (already implemented)
class TestRegularParameter {
constructor(x: number = x) {} // Should error: Parameter 'x' cannot reference itself (already works)
}

function regularFunction(param = param) {} // Should error: Parameter 'param' cannot reference itself (already works)

const arrowFunction = (param = param) => {}; // Should error: Parameter 'param' cannot reference itself (already works)
Loading