diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 66742c94f057e..8516da732d192 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 @@ -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) { diff --git a/tests/baselines/reference/parameterPropertySelfReference.errors.txt b/tests/baselines/reference/parameterPropertySelfReference.errors.txt new file mode 100644 index 0000000000000..e2d433ce43198 --- /dev/null +++ b/tests/baselines/reference/parameterPropertySelfReference.errors.txt @@ -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. + \ No newline at end of file diff --git a/tests/cases/compiler/parameterPropertySelfReference.ts b/tests/cases/compiler/parameterPropertySelfReference.ts new file mode 100644 index 0000000000000..b8776a93fe672 --- /dev/null +++ b/tests/cases/compiler/parameterPropertySelfReference.ts @@ -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)