Reject class-named members and unsupported constructor delegation

This commit is contained in:
sergeych committed 2026-10-20 23:57:41 +04:00
1 parent 26a1ca9710
commit 04c9343a9d
5 files changed
+155

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
### Ticket 1 — Name resolution: a member function named like its class silently shadows the primary constructor inside the class body
**Summary.** `class` bodies accept a member function whose name equals the class name. That member then wins name resolution for **all unqualified calls inside the class body**, including `init` blocks, method bodies and nested lambdas. The primary constructor becomes unreachable from inside the class, with no escape hatch. Compiles cleanly, breaks at runtime.
**Repro**
```lyng
class C1(x) {
fun C1(y): String = "member " + y.toString()
init { println(C1(9)) } // -> "member C1(9)", NOT the constructor
}
class C2(x) {
fun C2(y, z): String = y.toString() + z.toString()
fun probe(): String = C2(7, 8) // member chosen although ctor takes 1 arg
}
class Fact(x) {
fun Fact(y): Fact = Fact(y * 2) // compiles; unqualified Fact(...) = itself
}
Fact(1).Fact(3) // java.lang.StackOverflowError
```
Local functions shadow too:
```lyng
class M3(x) {
fun probe(y): String {
fun M3(z): String = "local " + z.toString()
return M3(y) // local member wins, ctor unreachable
}
}
```
No workaround found:
```lyng
class Q1(x) {
fun Q1(y): String = "member"
fun a(): String = Q1.Q1(3) // IllegalArgumentException: expected 1 arguments, got 0
fun b(): String = (Q1(5) as Q1).Q1(6) // ClassCastException: Cannot cast String to Q1
}
class G1(x) { fun g(): G1 = this(x + 1) } // Exception: operation is not implemented
```
Related symptom: adding `Type::class` in a class that also has a same-name member turns the **declaration** itself into a hard error pointing at the wrong place:
```lyng
class D16(x) {
fun D16(y): String = "member " + y.toString() // Error: expected 1 arguments, got 0
fun lit(): String = D16::class.toString()
}
```
Control cases compile fine: same-name member alone ✔, `::class` alone ✔, the combination ✘.
**Expected.** Either (a) reject a member whose name collides with the class name at compile time (preferred — it is never a constructor in Lyng, there are no secondary constructors), or (b) keep constructor calls resolvable for the primary arity and fall back to members only for non-matching arity, plus a working `this(...)`/`this@Type(...)` delegation. In any case `Type::class` must not be affected by a same-name member, and diagnostics must point at the actual construct.
**Suggested tests.** `fun SameName(...)` declared in a class with the same name → expected compile error; self-recursive factory → must not reach runtime stack overflow; `Type::class` inside such a class → must compile; `this(...)` → either implement or emit a clear compile-time error instead of `operation is not implemented`.
## Resolution
Valid: direct instance/static member functions named after their enclosing class
are now rejected at the function name. This also rejects the collision before
any `::class` expression can produce a misleading downstream diagnostic.
The supported control is `Type::class` in a class without the illegal member;
the suggested test asking the illegal declaration to compile contradicts the
report's preferred resolution.
Direct `this(...)` / `this@Type(...)` calls on the enclosing class instance now
report unsupported constructor delegation during compilation. Use `Type(...)`
to construct another instance; no secondary constructors were introduced.
Local functions shadowing class names are ordinary lexical shadowing, not a bug,
and remain supported. Regression coverage: `ClassNameMemberRegressionTest`.
Before the fix, 2 of its 4 tests failed; the constructor/class-literal and local
shadowing controls passed.
Validation: all 4 focused JVM regression tests passed, followed by the full
`:lynglib:jvmTest` suite (benchmarks excluded by the repository default).
+5
View File
@@ -0,0 +1,5 @@
# Invalid reports
Place reports here when reproduction and the language contract show that they
are not bugs. Append the reason and verification evidence to each moved report.
Valid reports with an invalid subclaim stay with their resolution notes.