Skip to content

Apply the version rule to the resource fallback (fixes CI on #76) - #77

Merged
ByronMayne merged 1 commit into
ByronMayne:75-resolvemissingassembly-fallback-ineffective-because-s_assemblieswithresources-was-never-populatedfrom
JesseKlaasse:fix/pr76-fallback-version-rule
Oct 4, 2026
Merged

ByronMayne merged 1 commit into
ByronMayne:75-resolvemissingassembly-fallback-ineffective-because-s_assemblieswithresources-was-never-populatedfrom
JesseKlaasse:fix/pr76-fallback-version-rule

Conversation

@JesseKlaasse

Copy link
Copy Markdown
Contributor

Targets the branch of #76, so merging this makes #76 green.

Why #76 fails CI

Populating s_assembliesWithResources brings the resource fallback in ResolveMissingAssembly to life. That fallback returns whatever it extracts, with no version check. So Request_For_A_Newer_Version_Does_Not_Resolve_To_An_Older_One (from #74) now gets the 1.0.0.0 copy for a 2.0.0.0 request:

Failed ConsoleApp.SourceGenerator.Tests.AssemblyResolverTests.Request_For_A_Newer_Version_Does_Not_Resolve_To_An_Older_One
  Assert.Throws() Failure: No exception was thrown

There is a second problem behind it: Assembly.Load(byte[]) loads a new copy on every call, and none of them unload. Each unsatisfied request adds another copy of an assembly that is already loaded. In a compiler server that lives for hours, that is a slow leak plus duplicate type identities.

Change

  • The fallback uses the same rule as the lookup above it (Satisfies: same name, at least the requested version). A copy that does not satisfy the request is still registered, but not returned.
  • Each resource is unpacked at most once, by AddAssembly or by the fallback, whichever comes first (s_extractedResources, under the existing s_assembliesWithResourcesLock).
  • The unused alreadyLoaded local is removed (CS0168 in the generated hoist; it shows up as a warning in every consumer's build).

The fallback still does what #75 asks for: it reaches a resource that AddAssembly has not unpacked yet. That can happen while another generator initialises on another thread, between s_assembliesWithResources.Add and the extract loop.

Tests

This also covers the Copilot note on #76: nothing exercised the fallback.

Test #76 as is With this
Request_For_A_Newer_Version_Does_Not_Resolve_To_An_Older_One (existing) ❌ ✅
Unsatisfied_Request_Does_Not_Load_The_Embedded_Assembly_Again ❌ ✅
Resource_Fallback_Unpacks_An_Embedded_Assembly_Not_Unpacked_Yet ✅ ✅
Resource_Fallback_Does_Not_Resolve_To_An_Older_Version ❌ ✅

The last two put the resolver in that window: they forget that one resource was unpacked, so only the fallback can reach it. Each guard was removed once to confirm its test fails:

  • version check in the fallback removed → Resource_Fallback_Does_Not_Resolve_To_An_Older_Version fails;
  • unpack-once removed → Unsatisfied_Request_… fails;
  • s_assembliesWithResources.Add removed (the state on master) → Resource_Fallback_Unpacks_… fails.

Locally, Release as in CI (.NET SDK 10.0.300): Sandbox tests 11/11, SourceGenerator.Foundations.Tests 3/3 (net6.0, rolled forward to 8.0), 0 warnings.

🤖 Generated with Claude Code

…urce once

With s_assembliesWithResources populated, the resource fallback runs, and
it had two problems that the lookup above it does not:

- It returned whatever it extracted, regardless of version: a request for
  2.0.0.0 got the 1.0.0.0 copy. That is what fails
  Request_For_A_Newer_Version_Does_Not_Resolve_To_An_Older_One in CI.
- Assembly.Load(byte[]) loads a new copy on every call and none unloads,
  so every unsatisfied request added another copy of an assembly that was
  already loaded.

The fallback now skips a copy that does not satisfy the request (same
Satisfies rule as the lookup), and a resource is unpacked at most once,
whether by AddAssembly or by the fallback (s_extractedResources).

Also removes the unused 'alreadyLoaded' local (CS0168).

Tests: an unsatisfied request does not load the assembly again; the
fallback unpacks a resource AddAssembly has not reached yet (the window
another generator initialising on another thread can hit), and does not
hand back an older version from there. Each fails with its guard removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ByronMayne
ByronMayne merged commit ea49e0c into ByronMayne:75-resolvemissingassembly-fallback-ineffective-because-s_assemblieswithresources-was-never-populated Oct 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants