Repository navigation
fix(js/ts/python): support explicit constructors with as and then - #5235
Conversation
Python Type Checking Results (Pyright)
Excluded files with errors (4 files)These files have known type errors and are excluded from CI. Remove from
|
There was a problem hiding this comment.
🟡 Changes recommended
Critical constructor-lowering defects break Rust and BEAM explicit constructors and leave inherited self references pointing to a separate base object rather than the derived instance.
4 open issues
What changed in this PR
This PR addresses #5166 by extending Fable’s shared F# lowering to support explicit constructors with as self bindings and then blocks.
Changes:
- Resolves constructor self references and preserves the constructed object after
thenexecution. - Supplies defaults for omitted compiler-generated fields and refactors base-constructor handling.
- Adds JavaScript and Python regression tests for side effects, constructor chaining, and inheritance.
| File | Description |
|---|---|
| tests/Python/TestType.fs | Adds explicit-constructor regression tests for Python. |
| tests/Js/Main/TypeTests.fs | Adds corresponding JavaScript constructor tests. |
| src/Fable.Transforms/FSharp2Fable.fs | Implements shared lowering for self bindings, then blocks, and omitted fields. |
Review effort: Balanced
7d1bbbc to
ca388e0
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Constructor generation can emit invalid duplicate parameters, while incomplete self-safety analysis can wrongly reject valid overloads or miss unsafe inheritance.
5 open issues
Ensure inherited initialization parameter names are unique · New Track watch dependencies for inspected constructor implementations · New Preserve constructor-safety information for precompiled libraries · New Traverse LetRec bodies when checking forwarded constructors · New Exclude generated initialization writes when detecting constructors that bind s… · New
4 resolved since last review
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
The inheritance checks incorrectly reject valid bases by analyzing ignored import/global constructor stubs and mistaking compiler-generated secondary-constructor writes or static initialization flags for explicit self bindings.
3 open issues
5 resolved since last review
Ensure inherited initialization parameter names are unique Exclude generated initialization writes when detecting constructors that bind s… Traverse LetRec bodies when checking forwarded constructors Preserve constructor-safety information for precompiled libraries Track watch dependencies for inspected constructor implementations
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
The inheritance check incorrectly rejects imported/global derived stubs whose local base has an explicit self constructor, breaking interop stubs even though their derived constructors are discarded.
1 open issue
3 resolved since last review
Review effort: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
Shared constructor lowering spans FCS expression shapes and three target emitters, requiring .NET/JS/TS/Python runtime validation of object identity, initialization order, and constructor chaining that could not be performed in this review environment.
No open issues 🎉
1 resolved since last review
Review effort: Balanced


Fixes #5166.
Explicit constructors with a self identifier (
new() as x = { ... } then ...) now work on JS, TS and Python, in a class with no base class. Constructors chaining within the class work too.These stay a compile error, as on main:
[<AttachMembers>].Inheriting needs the base
thenblock to run on the derived instance, tracked in #5272.Known gaps:
InvalidOperationException.let mutablesees a later field's change to it. Withoutas, main has the same bug.[<DefaultValue>]field doesn't get the type's default. Withoutas, main has the same bug..fsiisn't rejected, because the signature hides the field the check looks for.