Test case: System.AttributeUsageAttribute (System.Private.CoreLib) — select the type (or its .cctor) with the IL with C# language in a Debug build. An "Assertion Failed" dialog appears.
Assertion failed.
at ICSharpCode.Decompiler.CSharp.Transforms.TransformFieldAndConstructorInitializers.ConstructorInitializerAnalyzer.MoveFieldInitializersToDeclarations(InitializerSequence sequence, InitializerKind kind) in ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs:line 500
at ICSharpCode.Decompiler.CSharp.Transforms.TransformFieldAndConstructorInitializers.TransformDeclaration(...)
at ICSharpCode.Decompiler.CSharp.Transforms.TransformFieldAndConstructorInitializers.Run(...)
at ICSharpCode.Decompiler.CSharp.CSharpDecompiler.RunTransforms(...)
at ICSharpCode.Decompiler.CSharp.CSharpDecompiler.Decompile(IEnumerable`1 definitions)
Cause: CSharpILMixedLanguage.MixedMethodBodyDisassembler decompiles each method as a bare handle (CSharpDecompiler.Decompile(handle)). For a static constructor, MoveFieldInitializersToDeclarations then finds a static-field initializer statement whose target field has no FieldDeclaration in the partial syntax tree, hits Debug.Assert(kind is InitializerKind.Primary) (kind is Static), and removes the statement — so in Release builds the C# preview of the .cctor silently loses the field assignment.
The regular C# view is not affected because CSharpLanguage.DecompileMethod bundles the type's fields and ctors via CollectFieldsAndCtors before decompiling, so the declaration the initializer moves to is always present.
Standalone repro (Debug build of ICSharpCode.Decompiler; terminates on the failed assert):
var corlib = typeof(object).Assembly.Location;
var module = new PEFile(corlib);
var resolver = new UniversalAssemblyResolver(corlib, false, module.Metadata.DetectTargetFrameworkId());
var metadata = module.Metadata;
var td = metadata.TypeDefinitions.Select(metadata.GetTypeDefinition)
.Single(t => metadata.GetString(t.Name) == "AttributeUsageAttribute" && metadata.GetString(t.Namespace) == "System");
foreach (var mh in td.GetMethods())
new CSharpDecompiler(module, resolver, new DecompilerSettings()).Decompile(mh); // asserts on the .cctor
Observed on current master (0f9de78), Linux; not a recent regression — any single-member decompile of a static ctor whose type has static field initializers takes this path.
🤖 Generated with Claude Code
Test case:
System.AttributeUsageAttribute(System.Private.CoreLib) — select the type (or its.cctor) with the IL with C# language in a Debug build. An "Assertion Failed" dialog appears.Cause:
CSharpILMixedLanguage.MixedMethodBodyDisassemblerdecompiles each method as a bare handle (CSharpDecompiler.Decompile(handle)). For a static constructor,MoveFieldInitializersToDeclarationsthen finds a static-field initializer statement whose target field has noFieldDeclarationin the partial syntax tree, hitsDebug.Assert(kind is InitializerKind.Primary)(kind isStatic), and removes the statement — so in Release builds the C# preview of the.cctorsilently loses the field assignment.The regular C# view is not affected because
CSharpLanguage.DecompileMethodbundles the type's fields and ctors viaCollectFieldsAndCtorsbefore decompiling, so the declaration the initializer moves to is always present.Standalone repro (Debug build of ICSharpCode.Decompiler; terminates on the failed assert):
Observed on current master (0f9de78), Linux; not a recent regression — any single-member decompile of a static ctor whose type has static field initializers takes this path.
🤖 Generated with Claude Code