Recover ref/out/in on generic-instance and ref-readonly call sites#609
Merged
Conversation
A call on a constructed generic type resolves as a MemberReference with a TypeSpecification parent, which carries no parameter rows — so out/in were lost and rendered as ref (CS1620/CS1615), e.g. every `Dictionary<,>.TryGetValue(out v)` call. Recover them by resolving the MemberRef back to the underlying generic MethodDef (signature-blob match within the declaring TypeDef) and reading its parameter rows. Also fixes how by-ref kinds are classified and spelled: - `ref readonly` parameters (RequiresLocationAttribute) join `in` (IsReadOnlyAttribute) as readonly references — rendered without a mutable-ref keyword, valid for a readonly/rvalue argument. Previously a `ref readonly` ctor like `ReadOnlySpan<T>(ref readonly T)` was spelled `ref this` on a readonly receiver (CS1605). - `out`/`ref` arguments now require a genuine assignable lvalue; a cast (unbox) is not one, so `out (T)x` (CS0206) falls back to the default spelling. `in` still accepts a value form. Validated with the harness defect-diff: vs main, REGRESSED (none), IMPROVED CS1620 x2 and CS1605 x1. (The four spurious CS1615 from internal-overload calls are a compile-check shell artifact addressed separately by importing internals.) Tests: ILInspector.Decompiler.Tests 427 pass (a generic-instance out/in call site and the RefKindBox<T> fixture added). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Recovers call-site
ref/out/inkeywords that the pipeline was dropping, in two related cases the raising-pass review surfaced.Generic-instance calls
A call on a constructed generic type resolves as a
MemberReferencewith aTypeSpecificationparent, which carries no parameter rows — soout/inwere lost and rendered asref(CS1620/CS1615). The classic case: everyDictionary<,>.TryGetValue(out v)call. This resolves the MemberRef back to its underlying genericMethodDef(signature-blob match within the declaringTypeDef) and reads its parameter rows.Ref-kind classification / spelling
ref readonlyparameters (RequiresLocationAttribute) now joinin(IsReadOnlyAttribute) as readonly references — spelled without a mutable-ref keyword (valid for a readonly/rvalue argument). Previously aref readonlyctor likeReadOnlySpan<T>(ref readonly T)was renderedref thison a readonly receiver → CS1605.out/refarguments now require a genuine assignable lvalue; a cast (unbox) is not one, soout (T)x(CS0206) falls back to the default spelling.instill accepts a value.Validation
Harness defect-diff (
--diff-defects) vsmain, over the methods checked in both runs:A clean win. Decompiler tests 427 pass (adds a generic-instance
out/incall-site test and aRefKindBox<T>fixture).Dependency
Depends on #608 (compile-check: import internal members) for the clean scoreboard. Without it, four spurious CS1615 appear (
Array.Fill/Sort/UnsafeArrayAsSpan,String.JoinCore): the decompiledrefis correct, but it calls the internalSpan<T>(ref T, int)ctor that the external compile-check shell can't access, so Roslyn mis-binds and mis-reports. #608 makes those report CS0122 (filtered noise) instead. Merge #608 first.🤖 Generated with Claude Code