mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-09 03:17:54 +00:00
fix(javascript): type a class field from its initializer so it can be a receiver
JavaScript has no field annotations at all, so a class field's type can only ever come from its initializer — which made this the strictly worse half of #2807: `class C { p = new Outer(); }` gave `this.p` no type, and `this.p.inner()` emitted nothing. `synthesizeConstructorFieldBindings` in captures.ts already covered the sibling shape, `this.p = new Outer()`, which is why THAT row resolved — but it only walks `constructor` bodies, so a field initialized at its declaration matched no pattern anywhere. Adds the `field_definition` + `value: (new_expression)` patterns (the JS grammar names the field `property:`, not `name:`), anchored so the binding lands in the class body scope where `typeOfMemberOnClass` reads it. No hook change needed: `jsBindingScopeFor` already delegates to `tsBindingScopeFor`, so it inherits the `@type-binding.this-field` branch too. Measured: `InferredField.run` now emits `Outer.inner`, exact parity with both the local-const control and the constructor-assigned row. The second chain link (`Inner.compute`) stays absent in ALL THREE rows — that is JavaScript's separate return-type-inference gap, not this one. Refs #2807 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6869504408
commit
18a48c7313
1 changed files with 28 additions and 0 deletions
|
|
@ -430,6 +430,34 @@ export const JAVASCRIPT_SCOPE_QUERY = `
|
|||
value: (new_expression
|
||||
constructor: (member_expression) @type-binding.type)) @type-binding.constructor
|
||||
|
||||
;; Class field initializer: \`class C { p = new Outer(); }\` (#2807).
|
||||
;; JavaScript has no field annotations at all, so a class field's type can only
|
||||
;; ever come from its initializer — without this pattern \`this.p.inner()\` had
|
||||
;; nothing to type the receiver with and the receiver fold declined the whole
|
||||
;; chain. \`synthesizeConstructorFieldBindings\` in captures.ts already covers the
|
||||
;; sibling shape (\`this.p = new Outer()\`), but only inside a \`constructor\`
|
||||
;; body, so a field initialized at its declaration matched nothing.
|
||||
;;
|
||||
;; Anchored on \`field_definition\` so the binding lands in the class body scope,
|
||||
;; where \`typeOfMemberOnClass\` reads it — the same anchoring TypeScript uses for
|
||||
;; \`public_field_definition\`. Note the JS grammar names the field \`property:\`,
|
||||
;; not \`name:\`.
|
||||
(field_definition
|
||||
property: (property_identifier) @type-binding.name
|
||||
value: (new_expression
|
||||
constructor: (identifier) @type-binding.type)) @type-binding.constructor
|
||||
|
||||
(field_definition
|
||||
property: (property_identifier) @type-binding.name
|
||||
value: (new_expression
|
||||
constructor: (member_expression) @type-binding.type)) @type-binding.constructor
|
||||
|
||||
;; Private-name field: \`#p = new Outer()\`.
|
||||
(field_definition
|
||||
property: (private_property_identifier) @type-binding.name
|
||||
value: (new_expression
|
||||
constructor: (identifier) @type-binding.type)) @type-binding.constructor
|
||||
|
||||
;; Call-result alias: const u = getUser()
|
||||
(variable_declarator
|
||||
name: (identifier) @type-binding.name
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue