Reject class-named members and unsupported constructor delegation
This commit is contained in:
1 parent
26a1ca9710
commit
04c9343a9d
5 files changed
+155
No files matched your search
@@ -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).
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user