mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-04 07:27:20 +00:00
* fix(rust): see through Box, Rc and Arc on struct field types (#3498) The struct-field normalizer in rust/range-binding.ts cut a type at its first `<`. A `repo: Box<User>` field was typed `Box`, so `self.repo.save()` bound nothing. It also stripped a leading `&` but not a lifetime, so a borrowed field, which always carries one (`&'a User`), came out as `'a User`. Box, Rc and Arc auto-deref on a method call, so the field now takes their first type argument: bare or path-qualified (`std::rc::Rc<User>`), and nested (`Rc<Box<User>>`). Borrows with a lifetime or `mut` are stripped, and `Box<dyn Trait>` reduces to the trait through the stripDynBound helper that parameters already use (#2604). RefCell, Cell, Mutex, RwLock, Option and Vec are deliberately left alone. A method on the inner type needs `.borrow()`, `.get()`, `.lock()`, `.read()`, a match or an index first, so the receiver really is the wrapper, and a direct call through one must not bind. Shape arm: rust `decoratedFieldType` moves INVISIBLE-GAP -> RESOLVES, with the edge on `User::save`. The corpus has no smart-pointer or borrowed struct field, so the count arm and every other cell are unchanged, and the corpus edge (2838) and drop (192) sets match main exactly. Scope-capture fingerprints are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(rust): keep opaque pointer fields wrapped * fix(rust): refuse opaque macro expansions * test(rust): pin pointer wrapper targets and opacity limits (#3665) - Assert a same-file Box keeps its own save target while User.save stays unbound (review thread on custom same-named wrappers). - Pin the documented workspace-wide recall limit: an unrelated unresolved import or macro_rules! keeps an otherwise valid pointer field wrapped. - Drop per-case logging and group the opaque/expansion cases in describe blocks. - Collapse the stacked pointer-field receipts in BASELINE.md into one current section listing every workspace-wide refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: preserve Rust integration notes * test(rust): assert complete pointer targets --------- Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
2.5 KiB
TypeScript
53 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { getRelationships, runPipelineFromRepo, writeFixtureRepo } from './resolvers/helpers.js';
|
|
const custom = (name: string) =>
|
|
`mod custom { pub struct ${name}<T> { pub value:T } impl<T> ${name}<T> { pub fn save(&self) {} } }`;
|
|
const localBox = `struct Box<T> { value:T } impl<T> Box<T> { fn save(&self) {} }`;
|
|
describe('Rust field pointer ownership', () => {
|
|
it.each([
|
|
['custom Box', 'custom::Box<User>', custom('Box'), ['Function:src/lib.rs:custom.Box.save#0']],
|
|
['custom Rc', 'custom::Rc<User>', custom('Rc'), ['Function:src/lib.rs:custom.Rc.save#0']],
|
|
['custom Arc', 'custom::Arc<User>', custom('Arc'), ['Function:src/lib.rs:custom.Arc.save#0']],
|
|
['shadowed prelude Box', 'Box<User>', localBox, ['Function:src/lib.rs:Box.save#0']],
|
|
['foreign imported Rc', 'Rc<User>', 'use foreign::Rc;', []],
|
|
['nested custom Box', 'std::boxed::Box<custom::Box<User>>', custom('Box'), []],
|
|
['std qualified Box', 'std::boxed::Box<User>', '', ['Function:src/lib.rs:User.save#0']],
|
|
['std qualified Rc', 'std::rc::Rc<User>', '', ['Function:src/lib.rs:User.save#0']],
|
|
['std qualified Arc', 'std::sync::Arc<User>', '', ['Function:src/lib.rs:User.save#0']],
|
|
['prelude Box', 'Box<User>', '', ['Function:src/lib.rs:User.save#0']],
|
|
['imported standard Rc', 'Rc<User>', 'use std::rc::Rc;', ['Function:src/lib.rs:User.save#0']],
|
|
[
|
|
'imported standard Arc',
|
|
'Arc<User>',
|
|
'use std::sync::Arc;',
|
|
['Function:src/lib.rs:User.save#0'],
|
|
],
|
|
] as const)(
|
|
'%s',
|
|
async (_label, type, declaration, expectedTargets) => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-rust-pointer-'));
|
|
try {
|
|
writeFixtureRepo(root, {
|
|
'Cargo.toml': '[package]\nname="pointer_probe"\nversion="0.1.0"\nedition="2021"\n',
|
|
'src/lib.rs': `${declaration}
|
|
struct User; impl User { fn save(&self) {} }
|
|
struct Decoy; impl Decoy { fn save(&self) {} }
|
|
struct Host { repo: ${type} }
|
|
impl Host { fn probe(&self) { self.repo.save(); } }
|
|
`,
|
|
});
|
|
const result = await runPipelineFromRepo(root, () => {}, {});
|
|
const targets = getRelationships(result, 'CALLS')
|
|
.filter((e) => e.source === 'probe')
|
|
.map((e) => e.rel.targetId);
|
|
expect(targets).toEqual(expectedTargets);
|
|
} finally {
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
}
|
|
},
|
|
120000,
|
|
);
|
|
});
|