mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-20 00:11:37 +00:00
feat(python-scope): dict.items() value-type unwrapping
Two changes that together resolve `for k, v in data.items(): v.save()`: - `interpret.ts stripGeneric`: extends to `dict[K, V]` / `Dict[K, V]` / `Mapping[K, V]` etc., stripping to the value type V. Previously only single-arg generics (list[User] → User) were stripped; multi-arg ones returned the raw text. - `query.ts` + `scopes.scm`: new typeBinding patterns for `for k, v in X.items()` (both pattern_list and tuple_pattern). The second tuple element binds to X; the chain-follow then unwraps X's dict annotation to V via the new stripGeneric branch. Verification: - Flag-off: 191/191 (identical baseline). - Flag-on: 6 fail / 185 pass (was 7/184; +1 — `dict.items() loop` test now passes). - tsc --noEmit clean.
This commit is contained in:
parent
a04cc1732c
commit
a446751045
3 changed files with 59 additions and 2 deletions
|
|
@ -149,10 +149,22 @@ function stripForwardRefQuotes(text: string): string {
|
|||
* resolution time.
|
||||
*/
|
||||
function stripGeneric(text: string): string {
|
||||
const match = text.match(
|
||||
const single = text.match(
|
||||
/^(?:[A-Za-z_][A-Za-z0-9_]*\.)?(?:list|List|set|Set|tuple|Tuple|Iterable|Iterator|Sequence|Generator|AsyncIterable|AsyncIterator)\[([^,\]]+)\]$/,
|
||||
);
|
||||
return match !== null ? match[1].trim() : text;
|
||||
if (single !== null) return single[1].trim();
|
||||
// dict[K, V] / Dict[K, V] / Mapping[K, V] — strip to value type V.
|
||||
// For-loop destructuring of `for k, v in d.items()` binds `v` to
|
||||
// `d`; the chain-follow then unwraps the dict annotation to V.
|
||||
// Single-key dict `dict[K]` is not legal Python, so two args is the
|
||||
// only shape worth handling. Match a top-level K up to the first
|
||||
// comma and a V to the closing bracket; nested generics in V (e.g.
|
||||
// `dict[str, list[User]]`) are left for a downstream strip pass.
|
||||
const dict = text.match(
|
||||
/^(?:[A-Za-z_][A-Za-z0-9_]*\.)?(?:dict|Dict|Mapping|MutableMapping|OrderedDict|DefaultDict)\[[^,\]]+,\s*([^\]]+)\]$/,
|
||||
);
|
||||
if (dict !== null) return dict[1].trim();
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -144,6 +144,29 @@ export const PYTHON_SCOPE_QUERY = `
|
|||
(identifier) @type-binding.type))
|
||||
(#eq? @_enum "enumerate")) @type-binding.alias
|
||||
|
||||
;; for k, v in d.items() — bind v to d. The chain-follow unwraps d's
|
||||
;; dict[K, V] annotation to V via the dict-aware stripGeneric in
|
||||
;; interpret.ts. Covers both pattern_list and tuple_pattern shapes.
|
||||
(for_statement
|
||||
left: (pattern_list
|
||||
(identifier)
|
||||
(identifier) @type-binding.name)
|
||||
right: (call
|
||||
function: (attribute
|
||||
object: (identifier) @type-binding.type
|
||||
attribute: (identifier) @_items))
|
||||
(#eq? @_items "items")) @type-binding.alias
|
||||
|
||||
(for_statement
|
||||
left: (tuple_pattern
|
||||
(identifier)
|
||||
(identifier) @type-binding.name)
|
||||
right: (call
|
||||
function: (attribute
|
||||
object: (identifier) @type-binding.type
|
||||
attribute: (identifier) @_items))
|
||||
(#eq? @_items "items")) @type-binding.alias
|
||||
|
||||
;; Type bindings (variable annotations: \`u: User\` / \`u: User = x\`)
|
||||
(assignment
|
||||
left: (identifier) @type-binding.name
|
||||
|
|
|
|||
|
|
@ -158,6 +158,28 @@
|
|||
(identifier) @type-binding.type))
|
||||
(#eq? @_enum "enumerate")) @type-binding.alias
|
||||
|
||||
; for k, v in d.items() — bind v to d. The chain-follow unwraps d's
|
||||
; dict[K, V] annotation to V via the dict-aware stripGeneric.
|
||||
(for_statement
|
||||
left: (pattern_list
|
||||
(identifier)
|
||||
(identifier) @type-binding.name)
|
||||
right: (call
|
||||
function: (attribute
|
||||
object: (identifier) @type-binding.type
|
||||
attribute: (identifier) @_items))
|
||||
(#eq? @_items "items")) @type-binding.alias
|
||||
|
||||
(for_statement
|
||||
left: (tuple_pattern
|
||||
(identifier)
|
||||
(identifier) @type-binding.name)
|
||||
right: (call
|
||||
function: (attribute
|
||||
object: (identifier) @type-binding.type
|
||||
attribute: (identifier) @_items))
|
||||
(#eq? @_items "items")) @type-binding.alias
|
||||
|
||||
; ─── Type bindings: function return-type annotations ─────────────────────
|
||||
;
|
||||
; `def get_user() -> User:` — binds the function's NAME to its return
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue