diff --git a/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs b/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs index c389bdfba..5b7d792ab 100644 --- a/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs +++ b/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs @@ -608,9 +608,10 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator builder.AppendLine("\t}"); builder.AppendLine(); - // One CSharpSlotInfo static per slot; node.Slot compares against these by object identity. + // One typed CSharpSlotInfo static per slot; node.Slot compares against these by object + // identity, and the typed child accessors infer the child type from the slot. foreach (var s in slots) - builder.AppendLine($"\tpublic static readonly CSharpSlotInfo {s.PropertyName}Slot = new CSharpSlotInfo(\"{s.PropertyName}\", typeof({s.ElementType}), {(s.IsCollection ? "true" : "false")}, SlotKind.{s.KindName}, {(s.IsCollection || s.IsNullable ? "true" : "false")});"); + builder.AppendLine($"\tpublic static readonly CSharpSlotInfo<{s.ElementType}> {s.PropertyName}Slot = new CSharpSlotInfo<{s.ElementType}>(\"{s.PropertyName}\", {(s.IsCollection ? "true" : "false")}, SlotKind.{s.KindName}, {(s.IsCollection || s.IsNullable ? "true" : "false")});"); builder.AppendLine(); builder.AppendLine("\tinternal override CSharpSlotInfo GetChildSlotInfo(int index)"); diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/CSharpSlotInfo.cs b/ICSharpCode.Decompiler/CSharp/Syntax/CSharpSlotInfo.cs index ae6bc0a03..355714f8f 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/CSharpSlotInfo.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/CSharpSlotInfo.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax /// its parent, so node.Slot == X.YSlot identifies a node's position by object identity (the /// successor to node.Role == X.YRole). /// - public sealed class CSharpSlotInfo + public class CSharpSlotInfo { /// The slot's property name, e.g. "Left", "Body", "Parameters". public string Name { get; } @@ -64,4 +64,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax public override string ToString() => Name; } + + /// + /// A that carries its child type as a type parameter, so the typed + /// child accessors (node.GetChild(SomeNode.XSlot)) infer the result type from the slot + /// instead of needing an explicit type argument. is the child type (the + /// element type for a collection slot). + /// + public sealed class CSharpSlotInfo : CSharpSlotInfo where T : AstNode + { + internal CSharpSlotInfo(string name, bool isCollection, SlotKind kind, bool isOptional) + : base(name, typeof(T), isCollection, kind, isOptional) + { + } + } }