mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-21 00:21:30 +00:00
feat(csharp-scope): parity Unit 5d — cross-file typeBinding mirror
Closes 3 parity failures (15 → 12). `languages/csharp/namespace-siblings.ts`: extend the pass to mirror method return-type bindings from accessible sibling files' Module scopes into the importer's Module scope. "Accessible" = same-namespace siblings + `using namespace X;` targets. Without this mirror, `var u = svc.GetUser()` in App.cs couldn't chain-follow to User even after Unit 5b's module-scope hoist: `GetUser → User` lived on User.cs's Module scope, which isn't on the ancestor chain of App.cs's function scope, and `propagateImportedReturnTypes` only mirrors across explicit ImportEdge targets (not same-namespace implicit visibility). Closes: var-invocation return type, async/await u.Save (ambient namespace), cross-file return-type propagation (via u.Save / u.GetName in Program.cs). Python parity 204/204 on both flag paths; legacy C# 175/175; 12 C# parity failures remain.
This commit is contained in:
parent
ada782d350
commit
13086508e5
1 changed files with 44 additions and 0 deletions
|
|
@ -130,6 +130,50 @@ export function populateCsharpNamespaceSiblings(
|
|||
// for module-scope typeBindings).
|
||||
const finalized = indexes.bindings as Map<ScopeId, Map<string, BindingRef[]>>;
|
||||
|
||||
// Cross-namespace type-binding propagation: for each file, mirror
|
||||
// method return-type bindings from same-namespace sibling files and
|
||||
// from files in namespaces the importer `using`s, into the
|
||||
// importer's Module scope typeBindings. This enables
|
||||
// chain-follow from `var u = svc.GetUser()` → `GetUser → User`
|
||||
// even across files — without it the chain stalls at `GetUser`
|
||||
// because the return binding lives in the defining file's Module
|
||||
// scope, which isn't an ancestor of the importer's scope chain.
|
||||
for (const parsed of parsedFiles) {
|
||||
const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
|
||||
if (moduleScope === undefined) continue;
|
||||
const moduleTypeBindings = moduleScope.typeBindings as Map<
|
||||
string,
|
||||
import('gitnexus-shared').TypeRef
|
||||
>;
|
||||
|
||||
// Accessible namespaces = this file's own namespaces + every
|
||||
// `using namespace X;` target.
|
||||
const accessibleNamespaces = new Set<string>();
|
||||
const fileContent = inputs.fileContents.get(parsed.filePath) ?? '';
|
||||
NAMESPACE_RE.lastIndex = 0;
|
||||
let nm: RegExpExecArray | null;
|
||||
while ((nm = NAMESPACE_RE.exec(fileContent)) !== null) accessibleNamespaces.add(nm[1]!);
|
||||
if (accessibleNamespaces.size === 0) accessibleNamespaces.add('');
|
||||
for (const imp of parsed.parsedImports) {
|
||||
if (imp.kind === 'namespace' && imp.targetRaw !== null) {
|
||||
accessibleNamespaces.add(imp.targetRaw);
|
||||
}
|
||||
}
|
||||
|
||||
for (const nsName of accessibleNamespaces) {
|
||||
const bucket = buckets.get(nsName);
|
||||
if (bucket === undefined) continue;
|
||||
for (const scopeInfo of bucket.scopes) {
|
||||
if (scopeInfo.filePath === parsed.filePath) continue;
|
||||
if (scopeInfo.scope.kind !== 'Module') continue;
|
||||
for (const [boundName, typeRef] of scopeInfo.scope.typeBindings) {
|
||||
if (moduleTypeBindings.has(boundName)) continue;
|
||||
moduleTypeBindings.set(boundName, typeRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cross-namespace imports: for each file's `using X;` directive,
|
||||
// if `X` matches a known namespace bucket, inject that bucket's
|
||||
// classes into the importer's module scope. This is what makes
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue