Repository navigation
Conversation
…t that module (colbymchenry#3046) A Python call through a name the file imports as a module, like other.update(...) after `from pkg import other`, linked to the module's function whatever the calling function bound `other` to: a with/except/loop target, a walrus, a case capture, a lambda parameter or a comprehension variable. Parameters and plain assignments were already scoped. The Python walker now emits a function-scoped local binding row for loop, `with ... as`, `except ... as`, walrus and `case` capture targets, and for tuple and augmented assignment targets. A lambda parameter or comprehension variable binds only inside its own expression, narrower than the line-wide scope a row carries, so the resolver reads those from the syntax tree. Ported from upstream b700a3e
…is not User.save The fork's extractor emits an extends edge only for a plain or dotted base name, so `class Repo(Base[User])` never reached User.save. Adds upstream's regression test for that; the check that Base's own method is still reached through a parameterized base stays a todo, since the fork emits no edge for it. Ported from upstream cd04b21 (test only)
…k their method (colbymchenry#3049) A call to a method whose name ends in `!` or `?` on a receiver (`writer.flush!`, `writer.ready?`, `CacheWriter.create!(1)`) failed the method-call pattern. A method called straight on a new object (`CacheWriter.new(key).write_cache`, `Billing::Ledger.new.charge!`) was recorded with the receiver's raw text, arguments and blocks included, which no strategy matched. The Ruby walker now records a call on `Const.new(...)`, `A::B.new` or `::Foo.new` as `new Const().m`, the constructed-receiver shape other languages use. The resolver claims that shape ahead of name matching: the class by Ruby's constant lookup from the namespaces around the call, the method as the class's own instance method or the first its ancestry declares, and nothing when either is missing. The Ruby dot pattern takes a trailing `!` or `?`, the receiver-word scoring among several project methods of the name stays off for such names on a value receiver, and a module a call returns (`include RouteSet.new.tap {...}.url_helpers`) is no longer read as a mixin of the constant the call starts at. Ported from upstream 3a4cd3b
… to its class's method (colbymchenry#3053) Ported from upstream cdfa31b.
…ames the default (colbymchenry#3068) Ported from upstream ed6b88e
…'s own function (colbymchenry#3025) Ported from upstream 7021de5
…ares it (colbymchenry#3064) Ported from upstream cc17978
- A multiline `export default (\n v\n) => v` head is anonymous too: the classifier now reads from the marker's line to the end of the file, as upstream's readDefaultExport scans the whole statement, so an unfinished parenthesized head no longer counts as an expression default and wrongly enables the first-exported-function fallback. - A receiver proven to be an instance (`new C().m`, an `initialize`-typed `@x`) can only reach instance methods: an own class method no longer stands in for one an ancestor declares, so `Child.new.flush` reaches `Parent#flush` rather than `Child.flush` the class method. - A `Const.new` tail sliced at byte 200 could land inside a multibyte character and panic (caught per-ref, leaving the call unresolved); the regexes now read a char-boundary-safe prefix.
| .next() | ||
| .filter(|n| n.kind == "class"); | ||
| let method = match class { | ||
| Some(class) => self.ruby_method_of(&class.qualified_name, &c[3], r, "instance")?, |
There was a problem hiding this comment.
high: Preserve Ruby ancestor order for constructed receivers
The new receiver path calls ruby_method_of(..., "instance"), which collects ancestors, runs ancestors.sort(), and returns the first matching method. Alphabetical order replaces Ruby's inheritance order.
Failure: With class A; def run; end; end, class Z < A; def run; end; end, and class Child < Z; end, Child.new.run links to A#run instead of the override Z#run. Typed instance-variable receivers have the same failure.
Suggested fix: Use an ordered Ruby ancestry walk that checks the nearest superclass before its ancestors; add a regression with both parent and grandparent defining the method.
| "method" | "function" | "variable" | "constant" | "enum_member" | ||
| ) | ||
| && n.qualified_name == qualified | ||
| && Self::rust_crate_dir_of(&n.file_path, &graph) == own |
There was a problem hiding this comment.
medium: Verify the fallback member belongs to the resolved Rust type
The fallback accepts n.qualified_name == qualified and equal rust_crate_dir_of(...), then selects a candidate without resolving its impl's owner. Same-named types in different modules satisfy both checks.
Failure: Let a.rs declare Handle, a separate impls.rs implement a trait with a default current() for that Handle, and b.rs declare another Handle with an inherent current(). A valid crate::a::Handle::current() call misses rust_method_on because its provided-method scan only reads the declaration file. This new fallback then links the call to b::Handle::current.
Suggested fix: Resolve each candidate impl's owner and compare declaration IDs with ty, as rust_method_on already does. Leave the call unresolved when no candidate belongs to that type.
| if re!(r"^[A-Za-z_$][\w$]*[ \t]*=>").is_match(rest) { | ||
| return true; | ||
| } | ||
| if rest.starts_with('(') { |
There was a problem hiding this comment.
medium: Classify anonymous defaults from syntax rather than their text prefix
Only an identifier followed by => or text starting with ( is recognized as an arrow. export default /* comment */ () => 2 reaches the final false, enabling default_fn_class.
Failure: A module containing export function helper() { return 1; } followed on another line by export default /* comment */ () => 2; makes a consumer's default-import call link to helper. The default is an unrelated anonymous arrow. Generic TypeScript arrows such as export default <T>(x: T) => x are also misclassified.
Suggested fix: Inspect the marked export statement's AST value and exclude anonymous arrow/function/class expressions before enabling the fallback.
| target_names(alias, &mut targets); | ||
| } | ||
| } | ||
| "named_expression" => { |
There was a problem hiding this comment.
medium: Keep lambda-body walrus bindings inside the lambda
named_expression targets are emitted with self.enclosing_scope(), while the walker descends into lambdas without creating a lambda scope. New runtime evidence contradicts the earlier reply: Python compiles the lambda's assignment as STORE_FAST other, while the enclosing function reads other with LOAD_GLOBAL.
Failure: After from pkg import other, a function containing thunk = lambda: (other := {}) followed by other.persist() receives a false function-local binding for other. The import resolver rejects the actual module binding and loses the module call edge. Invoking the lambda does not change that module binding either.
Suggested fix: Scope walrus targets in lambda bodies to the lambda, while retaining the containing-scope rule for comprehension walruses.
Summary
Batch 3a of the upstream reconciliation line (upstream
colbymchenry/codegraphthrough69af19ac), eight ports into the fork's Rust-kernel resolution path. Continues #598 (batch 2) and #600 (batch 3c); batch 3b follows on its own branch.01acfc4dcec50372Repo.save()is notUser.savee24528d9!/?methods and calls on what.newmade link their method21397fd7initializetypes links to its class's methodf57fd223<script />no longer swallows the next script7a7a2ab8export defaultline inside a template literal no longer names the default96166c33usenames reach that type's own function0e85f46d#[path]attribute loads is the module that declares itFork adaptations (deliberate deviations from upstream)
f57fd223: consolidated sharedSFC_SCRIPT_ELEMENT/SFC_SCRIPT_OR_STYLE_ELEMENT/sfcBlockLineRangesexports insfc-script.ts, used by the Vue, Svelte, and Astro extractors plus syntax-token and vue-template masking — upstream patches each extractor separately.7a7a2ab8: upstream scans template-literal source text; the kernel parses defaults from AST bindings so the template-text skip is structural. The real port added upstream'sdefaultFnClassexpression-default fallback, gated on anonymous-vs-expression head classification.96166c33/0e85f46d:#[path]/cfg_attrmodule claims anduse-bound type paths implemented inrust_paths.rs/rust_modules.rs/rust_types.rsagainst the fork's resolved-edge model rather than upstream's source-scan model;rust_super_modulestops above target roots and the 2015 crate-root fallback is blocked by path modules.Validation
#[path]5/8 red on7a7a2ab8, type-member paths red on parent).dumpdiff (20-lang torture corpus)tsc --noEmitclean; kernelcargo check+ release build cleaneval:precisionon vite held (6/6 + 2/2); no Rust corpus exists in the eval set — noted upstream A/B link deltas (fast-mlsirm, dioxus, tokio) not reproduced locallyNot verified
#[path]modules — coverage is via the 8 regression tests, not dump diffs.