mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
A dynamic call site that names a type passes typeof(T) as its target. When a later argument contains control flow, the compiler stores that typeof in a temporary. ILInlining does not undo this: it inlines a store only into the immediately following instruction, so an intervening statement leaves the typeof behind, and the expression builder printed the temporary instead of the type. Substituting the typeof back into the target slot is not an option either, because a call there has side effects and blocks inlining of the remaining arguments. The type is therefore stored on the instruction. Object creation already did this, but kept the field private, so the expression builder re-derived the type from the target argument and failed on the spilled form. Member invocation gets the same field. Both drop the target from Arguments, so the dead-argument handling removes the store; ArgumentInfo keeps its entry for the target, because the invocation symbol is built from it. The type of an object creation is not nullable: the transform returns before constructing the instruction when it cannot match the typeof, and substitutes the unknown type otherwise. An unresolvable type therefore reaches the expression builder as the unresolved type it is, and prints as `?` like any other, rather than being indistinguishable from a missing one. Those two are also the only binder method kinds that ever see CSharpArgumentInfoFlags.IsStaticType. Every other way of naming a type as the receiver binds statically and leaves only a conversion of the dynamic operand behind. Assisted-by: Claude:claude-opus-5[1m]:Claude Code