From fbfb8ef98cdf68546654d62ed285ee672690eb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Gro=C3=9F?= Date: Sat, 31 Oct 2026 08:28:44 +0100 Subject: [PATCH 1/2] fix: keep an overload of a generated member that differs by arity or ref kind ValueObjectDeclaration.MethodsWithSignature and ClosedSetTypes.SameParameters matched a hand-written method to a generated one by name and parameter types alone. A generic Parse(string, IFormatProvider?), a From(in int) or From(ref int), a TryParse whose last parameter is by value, a generic or by-value TryFormat, and a closed set's generic Parse or by-value TryParse were refused as the generated member written by hand (CMTK1011), on the type and on a base record or base class, though C# overloads by each and Metalama introduces the generated member beside it (measured in a scratch consumer: every row builds and calls the generated member, no LAMA error). Both now match only a method without type parameters, and compare each parameter's ref kind: by reference where the generated one is out, by value where it is by value. ref or in against out is no overload in C# (CS0663) and nullability none at all, so those stay CMTK1011. Input class (GTS): a method that shares a generated member's name and parameter types, by what differs (arity; in, ref or out against by value; ref and in against out; nullability) and where it is declared (the type, a base record of this assembly and of another, a closed set and its base class), over the declaration shapes the check reads (record struct, sealed record class, closed set). 34 rows in OverloadTests build and call the generated member, 10 reach the hand-written overload, and 8 controls in BuildOutcomeTests stay refused. The wrapped type only enters the check as From's parameter, so the rows wrap int, which has every generated parse and format. Siblings found by the same catalogue on the other signature checks (TryFrom, Revalidate, CompareTo, Equals, GetHashCode, PrintMembers, ToString()) are the next commit. Reverting the source refuses all 16 new value objects and sets in the test project (32 CMTK1011); comparing ref kinds exactly (ref against out as another method) fails the 6 ref and in controls and Every_error_is_one_of_ the_intended_ones. FabricTests looked up From and TryFrom by name, which an overload made ambiguous; it looks them up by signature. The surface snapshot renders a generic method's type parameters and a ref or in parameter, so an overload no longer reads as a duplicate line; Match gains . Closes #226 Defect-Class: GTS Found-By: OR Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + design/aspects.md | 6 + .../ClosedSetTypes.cs | 20 +- src/CodoMetis.TypeKit.Generators/README.md | 10 +- .../ValueObjectDeclaration.cs | 36 +- .../Probes.cs | 17 + .../BuildOutcomeTests.cs | 38 + .../FabricTests.cs | 3 +- .../GeneratedSurface.verified.txt | 841 +++++++++++++++++- .../GeneratedSurfaceTests.cs | 14 +- .../OverloadTests.cs | 281 ++++++ test/oracles/claims.json | 29 + 12 files changed, 1246 insertions(+), 50 deletions(-) create mode 100644 test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 59a6066..bb41446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ section is the GitHub release's notes. - Generators: a `CompareTo(TSelf)`, `CompareTo(object)`, `TryFrom` or `Revalidate` a value object inherits from a base record now fails the build (CMTK1008, CMTK1011), so your build can fail when you upgrade. It stood in for the generated member: an inherited `CompareTo` made `<` overflow the stack and an EF Core query order by the column, and an inherited `TryFrom` need not run `Create`. Declare it on the value object ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). - Generators: a closed set over a base class that declares a member the generators add now fails the build with CMTK1011 naming it, where it failed with a Metalama error that named nothing you wrote: its `Parse`, `TryParse`, `Match` or `All`, and an `IParsable` it implements. A base class's `ToString()` that isn't sealed now fails the build too (CMTK1011), so your build can fail when you upgrade: the generated `ToString()` replaced it without a word. Declare `ToString()` in the set, or seal the base's, which is then kept ([Closed sets](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#closed-sets)). - Generators: `IValueObject`, `IValueObjectMaterializer` or `IPlainValueObject` declared through an interface of yours, such as an `IEntityId : IValueObject`, or by a base record now fails with CMTK1011 naming that interface, where it failed with a Metalama error (LAMA0512) that named nothing you wrote. To constrain generic code, use `IValueObject` itself ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). +- Generators: an overload of a generated member that C# tells apart by its type parameters, or by a parameter that is `ref`, `in` or `out` where the generated one's isn't (or the other way round), is now kept beside the generated member, on a value object, a closed set or a base of either, where the build failed with CMTK1011: a `Parse(string, IFormatProvider?)`, a `From(in int)`, a `TryParse` whose last parameter isn't `out` ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). ## 2.3.0 — 2026-10-29 diff --git a/design/aspects.md b/design/aspects.md index dc7ef6a..e4c4048 100644 --- a/design/aspects.md +++ b/design/aspects.md @@ -184,6 +184,12 @@ members of a generated name or signature and its `IParsable` are CMTK1011, its `sealed` `ToString()` is the seam and one not sealed is CMTK1011 (#205). Not refused: an interface's `==`, which the record's own replaces anyway, and `INumberBase`'s UTF-8 bridges. + - **A signature is what C# overloads by (#226).** A hand-written method matches a generated one only with no type + parameters, as the generated one has none, and with each parameter by reference where the generated one's is + `out` and by value where it is by value. A generic `Parse(string, IFormatProvider?)`, a `From(in int)` + and a `TryParse` whose last parameter is by value were CMTK1011, on the type, a base record and a closed set, + though Metalama introduces the generated member beside each (measured 2026-10-31). `ref` or `in` against `out` is + no overload in C# (CS0663), and nullability none at all, so both stay CMTK1011. - **Equality over a base record is generated (decided 2026-10-14, [decision 75](adr/0075-equality-over-base-record-generated.md)).** A derived record's synthesized equality calls the base's, which compares the base's fields and whatever the base declares. A base comparing by reference made two value objects holding 42 unequal diff --git a/src/CodoMetis.TypeKit.Generators/ClosedSetTypes.cs b/src/CodoMetis.TypeKit.Generators/ClosedSetTypes.cs index 6deb354..f152439 100644 --- a/src/CodoMetis.TypeKit.Generators/ClosedSetTypes.cs +++ b/src/CodoMetis.TypeKit.Generators/ClosedSetTypes.cs @@ -203,8 +203,9 @@ private static string WithoutComments(string text) /// public static IReadOnlyList GeneratedMembersDeclaredByHand(INamedType set, IReadOnlyList members) { - var text = TypeFactory.GetType(SpecialType.String); - var boolean = TypeFactory.GetType(SpecialType.Boolean); + (IType, bool) text = (TypeFactory.GetType(SpecialType.String), false); + (IType, bool) boolean = (TypeFactory.GetType(SpecialType.Boolean), false); + (IType, bool) result = (set, true); var parsable = TypeFactory.GetNamedType(typeof(IParsable<>)).WithTypeArguments(set); var memberNames = new HashSet(members.Select(member => member.ToDisplayString())); var generatedNames = GeneratedNames(set); @@ -222,7 +223,7 @@ .. bases.SelectMany(type => type.Fields.Concat(type.Properties).Concat( .Where(member => member is { IsImplicitlyDeclared: false, IsExplicitInterfaceImplementation: false } && member.Accessibility != Accessibility.Private && generatedNames.Contains(member.Name)) .Select(member => $"{member.ToDisplayString()} in its base type {type.ToDisplayString()}")), .. Declared(type => type.Methods.Where(method => IsOwn(method) && method.Name == "Parse" && (SameParameters(method, text) || SameParameters(method, text, boolean)))), - .. Declared(type => type.Methods.Where(method => IsOwn(method) && method.Name == "TryParse" && (SameParameters(method, text, set) || SameParameters(method, text, boolean, set)))), + .. Declared(type => type.Methods.Where(method => IsOwn(method) && method.Name == "TryParse" && (SameParameters(method, text, result) || SameParameters(method, text, boolean, result)))), .. Declared(type => type.Methods.Where(method => IsOwn(method) && IsGeneratedMatch(method, members.Count))), .. ValueObjectDeclaration.ImplementationsOf(set, [TypeFactory.GetNamedType(typeof(IClosedSet<>))]), .. set.ImplementedInterfaces.Where(implemented => implemented.Equals(parsable)).Select(implemented => $"the interface {implemented.ToDisplayString()}"), @@ -243,10 +244,15 @@ .. set.Attributes.Where(attribute => attribute.Type.Equals(TypeFactory.GetNamedT private static bool IsOwn(IMethod method) => method is { IsImplicitlyDeclared: false, IsExplicitInterfaceImplementation: false }; - /// Parameter types equal, nullability aside: Metalama refuses to introduce a method beside one of the same signature. - private static bool SameParameters(IMethod method, params IType[] types) => - method.Parameters.Count == types.Length - && method.Parameters.Select(parameter => parameter.Type.ToNonNullable()).Zip(types, (declared, expected) => declared.Equals(expected.ToNonNullable())).All(same => same); + /// + /// Parameter types equal, nullability aside, and each by reference where the generated one is out, in a + /// method without type parameters: Metalama refuses to introduce a method beside one of the same signature. A + /// generic Parse<T>(string) or a TryParse(string?, TSelf) is another method (#226). + /// + private static bool SameParameters(IMethod method, params (IType Type, bool Out)[] parameters) => + method.TypeParameters.Count == 0 + && method.Parameters.Count == parameters.Length + && method.Parameters.Zip(parameters, (declared, expected) => declared.Type.ToNonNullable().Equals(expected.Type.ToNonNullable()) && declared.RefKind != RefKind.None == expected.Out).All(same => same); /// The generated Match<TResult>: one Func<TResult> per member. private static bool IsGeneratedMatch(IMethod method, int memberCount) => diff --git a/src/CodoMetis.TypeKit.Generators/README.md b/src/CodoMetis.TypeKit.Generators/README.md index 3a248e8..90bc280 100644 --- a/src/CodoMetis.TypeKit.Generators/README.md +++ b/src/CodoMetis.TypeKit.Generators/README.md @@ -239,6 +239,12 @@ covers: `MaxValue` would stand in for the generated one, and generic code calling `T.MaxValue` would reach it. The error names the base. +An overload of a generated member is yours, and the generated one sits beside it. C# tells two methods +apart by their type parameters and by whether a parameter is `ref`, `in` or `out`, so a +`Parse(string, IFormatProvider?)`, a `From(in int value)` or a `TryParse` whose last parameter +isn't `out` is kept, on the value object or a base record. A `ref` or `in` where the generated member has +`out` is the same method to C#, as a different nullability is, so it fails the build like the member itself. + Two explicit implementations in an interface are fine, because a value object loses nothing by replacing them. A record's own `==` and `!=` replace an interface's, generated or not. And .NET's `INumberBase` formats and parses UTF-8 through the UTF-16 members, which every .NET number @@ -462,8 +468,8 @@ public sealed partial class OrderStatus : IClosedSet, IParsable(string name)`, is kept too. Any other generated member written by hand fails the build (CMTK1011), in the set or in a class it derives from. - **A base class's `ToString()`.** A `sealed` one is kept, since C# keeps it in every derived class. One that isn't sealed fails the build (CMTK1011), because the generated `ToString()` would replace diff --git a/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs b/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs index 7dbd478..da158d3 100644 --- a/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs +++ b/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs @@ -210,12 +210,15 @@ IEnumerable Declared(Func> find) => if (kind == ValueObjectKind.Plain) { - found.AddRange(Declared(type => MethodsWithSignature(type, "From", valueType))); + found.AddRange(Declared(type => MethodsWithSignature(type, "From", (valueType, false)))); found.AddRange(Declared(type => MembersNamed(type, methods: false, "From"))); } - var stringType = TypeFactory.GetType(SpecialType.String); - var provider = TypeFactory.GetType(typeof(IFormatProvider)); + // A generated method's parameters, and whether each is out: an overload that takes one by value where the + // generated one takes it by reference, or the other way round, is another method (#226). + (IType, bool) stringType = (TypeFactory.GetType(SpecialType.String), false); + (IType, bool) provider = (TypeFactory.GetType(typeof(IFormatProvider)), false); + (IType, bool) result = (target, true); // ValueObjectParsableAspect and, where parsing is generated, ValueObjectTypeConverterAspect. var parse = ValueObjectParsableAspect.ResolveStrategy(valueType); @@ -223,7 +226,7 @@ IEnumerable Declared(Func> find) => if (parse != ValueParseStrategy.Unsupported) { found.AddRange(Declared(type => MethodsWithSignature(type, "Parse", stringType, provider))); - found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", stringType, provider, target))); + found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", stringType, provider, result))); found.AddRange(Declared(type => MembersNamed(type, $"{target.Name}TypeConverter"))); generatedInterfaces.Add(TypeFactory.GetNamedType(typeof(IParsable<>))); @@ -231,18 +234,18 @@ IEnumerable Declared(Func> find) => { generatedInterfaces.Add(TypeFactory.GetNamedType(typeof(ISpanParsable<>))); - var span = TypeFactory.GetType(typeof(ReadOnlySpan)); + (IType, bool) span = (TypeFactory.GetType(typeof(ReadOnlySpan)), false); found.AddRange(Declared(type => MethodsWithSignature(type, "Parse", span, provider))); - found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", span, provider, target))); + found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", span, provider, result))); } if (ValueObjectParsableAspect.SupportsUtf8(valueType)) { generatedInterfaces.Add(TypeFactory.GetNamedType(typeof(IUtf8SpanParsable<>))); - var utf8 = TypeFactory.GetType(typeof(ReadOnlySpan)); + (IType, bool) utf8 = (TypeFactory.GetType(typeof(ReadOnlySpan)), false); found.AddRange(Declared(type => MethodsWithSignature(type, "Parse", utf8, provider))); - found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", utf8, provider, target))); + found.AddRange(Declared(type => MethodsWithSignature(type, "TryParse", utf8, provider, result))); } } @@ -254,13 +257,13 @@ IEnumerable Declared(Func> find) => if (ValueObjectFormattableAspect.ResolveStrategy(valueType) == ValueFormatStrategy.SpanFormattable) { - found.AddRange(Declared(type => MethodsWithSignature(type, nameof(ISpanFormattable.TryFormat), TypeFactory.GetType(typeof(Span)), TypeFactory.GetType(SpecialType.Int32), TypeFactory.GetType(typeof(ReadOnlySpan)), provider))); + found.AddRange(Declared(type => MethodsWithSignature(type, nameof(ISpanFormattable.TryFormat), (TypeFactory.GetType(typeof(Span)), false), (TypeFactory.GetType(SpecialType.Int32), true), (TypeFactory.GetType(typeof(ReadOnlySpan)), false), provider))); generatedInterfaces.Add(TypeFactory.GetNamedType(typeof(ISpanFormattable))); } if (ValueObjectFormattableAspect.SupportsUtf8(valueType)) { - found.AddRange(Declared(type => MethodsWithSignature(type, nameof(IUtf8SpanFormattable.TryFormat), TypeFactory.GetType(typeof(Span)), TypeFactory.GetType(SpecialType.Int32), TypeFactory.GetType(typeof(ReadOnlySpan)), provider))); + found.AddRange(Declared(type => MethodsWithSignature(type, nameof(IUtf8SpanFormattable.TryFormat), (TypeFactory.GetType(typeof(Span)), false), (TypeFactory.GetType(SpecialType.Int32), true), (TypeFactory.GetType(typeof(ReadOnlySpan)), false), provider))); generatedInterfaces.Add(TypeFactory.GetNamedType(typeof(IUtf8SpanFormattable))); } } @@ -678,11 +681,18 @@ internal static IEnumerable MembersNamed(INamedType target, bool methods /// whatever they return: a generated member with that signature is either refused by Metalama or /// skipped in favour of the hand-written one. /// - private static IEnumerable MethodsWithSignature(INamedType target, string name, params IType[] parameters) => + /// + /// The signature C# overloads by (#226): no type parameters, as the generated method has none, and each + /// parameter by reference where the generated one is out, by value where it is by value. A generic + /// Parse<TFormat>(string, IFormatProvider?), a From(in int) and a TryParse whose + /// last parameter is by value are other methods, which the generated ones sit beside. ref or in + /// against out is no overload in C# (CS0663), so it is the same method, as nullability is. + /// + private static IEnumerable MethodsWithSignature(INamedType target, string name, params (IType Type, bool Out)[] parameters) => target.Methods - .Where(method => method is { IsImplicitlyDeclared: false, IsExplicitInterfaceImplementation: false } + .Where(method => method is { IsImplicitlyDeclared: false, IsExplicitInterfaceImplementation: false, TypeParameters.Count: 0 } && method.Name == name && method.Parameters.Count == parameters.Length - && method.Parameters.Select(parameter => parameter.Type).Zip(parameters, (declared, expected) => declared.Equals(expected)).All(same => same)) + && method.Parameters.Zip(parameters, (declared, expected) => declared.Type.Equals(expected.Type) && declared.RefKind != RefKind.None == expected.Out).All(same => same)) .Select(method => method.ToDisplayString()); } diff --git a/test/CodoMetis.TypeKit.Generators.Probes/Probes.cs b/test/CodoMetis.TypeKit.Generators.Probes/Probes.cs index e4c3c36..45ef516 100644 --- a/test/CodoMetis.TypeKit.Generators.Probes/Probes.cs +++ b/test/CodoMetis.TypeKit.Generators.Probes/Probes.cs @@ -186,6 +186,23 @@ public override void Write(System.Text.Json.Utf8JsonWriter writer, ProbeSpanText /// public abstract record ProbeRecordBase; +/// +/// A base record in another assembly whose methods share a generated member's name and parameter types, but are +/// other methods to C#: a generic Parse, a From that takes its value by in, and a +/// TryParse whose last parameter is by value. The generated members sit beside them (#226). +/// +public abstract record ProbeOverloadingRecord +{ + /// A generic overload, never the generated Parse. + public static TSelf Parse(string text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// An overload by in, never the generated From. + public static TSelf From(in int value) => throw new NotSupportedException("hand-written"); + + /// An overload whose last parameter is by value, never the generated TryParse. + public static bool TryParse(string? text, IFormatProvider? provider, TSelf fallback) => throw new NotSupportedException("hand-written"); +} + /// /// A base record in another assembly for the test assembly's value objects, whose sealed /// ToString() is the formatting seam: C# keeps it in every derived record. diff --git a/test/CodoMetis.TypeKit.Generators.Tests/BuildOutcomeTests.cs b/test/CodoMetis.TypeKit.Generators.Tests/BuildOutcomeTests.cs index 5c81867..a726059 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/BuildOutcomeTests.cs +++ b/test/CodoMetis.TypeKit.Generators.Tests/BuildOutcomeTests.cs @@ -183,6 +183,8 @@ public void A_member_name_the_generators_take_is_refused_with_the_reason(string [InlineData("SetOverParsingBase", "ParsingSetBase.Parse(string) in its base type ParsingSetBase")] [InlineData("SetOverIgnoreCaseParsingBase", "IgnoreCaseParsingSetBase.Parse(string, bool) in its base type IgnoreCaseParsingSetBase")] [InlineData("SetOverTryParsingBase", "TryParsingSetBase.TryParse(string?, bool, out SetOverTryParsingBase) in its base type TryParsingSetBase")] + [InlineData("SetWithTryParseByRef", "SetWithTryParseByRef.TryParse(string?, ref SetWithTryParseByRef)")] + [InlineData("SetOverTryParsingByRefBase", "TryParsingByRefSetBase.TryParse(string?, bool, ref SetOverTryParsingByRefBase) in its base type TryParsingByRefSetBase")] [InlineData("SetOverMatchingBase", "MatchingSetBase.Match(Func) in its base type MatchingSetBase")] [InlineData("SetOverParsableBase", "the interface IParsable in its base type ParsableSetBase")] [InlineData("SetOverAllListingBase", "AllListingSetBase.All in its base type AllListingSetBase")] @@ -338,6 +340,10 @@ public void A_part_a_source_generator_adds_does_not_count() => [InlineData("HandWrittenParse", "HandWrittenParse.Parse(string, IFormatProvider?)")] [InlineData("HandWrittenParseOverASet", "HandWrittenParseOverASet.Parse(string, IFormatProvider?)")] [InlineData("HandWrittenFormat", "HandWrittenFormat.ToString(string?, IFormatProvider?)")] + [InlineData("TryParseByRef", "TryParseByRef.TryParse(string?, IFormatProvider?, ref TryParseByRef)")] + [InlineData("TryParseByIn", "TryParseByIn.TryParse(string?, IFormatProvider?, in TryParseByIn)")] + [InlineData("ParseOfOtherNullability", "ParseOfOtherNullability.Parse(string?, IFormatProvider)")] + [InlineData("TryFormatByRef", "TryFormatByRef.TryFormat(Span, ref int, ReadOnlySpan, IFormatProvider?)")] [InlineData("HandWrittenMinValue", "HandWrittenMinValue.MinValue")] [InlineData("HandWrittenJsonConverter", "the attribute JsonConverter")] [InlineData("HandWrittenTypeConverter", "the attribute TypeConverter")] @@ -495,6 +501,7 @@ public void One_Create_over_a_base_record_is_not_refused(string type) => [InlineData("CMTK1011", "InheritsPublicFormatting", "PublicFormattingBase.ToString(string?, IFormatProvider?) in its base type PublicFormattingBase")] [InlineData("CMTK1008", "InheritsPublicObjectOrder", "PublicObjectOrderBase.CompareTo(object?) in its base type PublicObjectOrderBase")] [InlineData("CMTK1011", "InheritsPublicParsing", "PublicParsingBase.Parse(string, IFormatProvider?) in its base type PublicParsingBase")] + [InlineData("CMTK1011", "InheritsTryParseByRef", "TryParseByRefBase.TryParse(string?, IFormatProvider?, ref InheritsTryParseByRef) in its base type TryParseByRefBase")] [InlineData("CMTK1011", "InheritsMinMaxNames", "MinMaxNamesBase.MinValue in its base type MinMaxNamesBase")] [InlineData("CMTK1011", "InheritsValueName", "ValueNameBase.Value in its base type ValueNameBase")] [InlineData("CMTK1011", "InheritsFromName", "FromNameBase.From(int) in its base type FromNameBase")] @@ -1043,6 +1050,27 @@ public static Result Create(string value) => public string ToString(string? format, System.IFormatProvider? provider) => ""; } + // No overload in C#: ref or in against the generated out (CS0663), and another nullability (#226). + public readonly partial record struct TryParseByRef : IValue + { + public static bool TryParse(string? s, System.IFormatProvider? provider, ref TryParseByRef result) => throw new System.NotSupportedException(); + } + + public readonly partial record struct TryParseByIn : IValue + { + public static bool TryParse(string? s, System.IFormatProvider? provider, in TryParseByIn result) => throw new System.NotSupportedException(); + } + + public readonly partial record struct ParseOfOtherNullability : IValue + { + public static ParseOfOtherNullability Parse(string? s, System.IFormatProvider provider) => throw new System.NotSupportedException(); + } + + public readonly partial record struct TryFormatByRef : IValue + { + public bool TryFormat(System.Span destination, ref int charsWritten, System.ReadOnlySpan format, System.IFormatProvider? provider) => false; + } + public readonly partial record struct HandWrittenMinValue : IValue { public static int MinValue => 0; @@ -1511,6 +1539,13 @@ public abstract record PublicParsingBase : System.IParsable where public sealed partial record InheritsPublicParsing : PublicParsingBase, IValue; + public abstract record TryParseByRefBase + { + public static bool TryParse(string? s, System.IFormatProvider? provider, ref TSelf result) => throw new System.NotSupportedException(); + } + + public sealed partial record InheritsTryParseByRef : TryParseByRefBase, IValue; + public abstract record MinMaxNamesBase where TSelf : MinMaxNamesBase { public static TSelf MinValue => throw new System.NotSupportedException(); @@ -2042,6 +2077,9 @@ public abstract class OpenToStringSetBase { public override string ToString() => public sealed partial class SetOverIgnoreCaseParsingBase : IgnoreCaseParsingSetBase, IClosedSet { public static readonly SetOverIgnoreCaseParsingBase A = new(); } public abstract class TryParsingSetBase { public static bool TryParse(string? name, bool ignoreCase, out TSelf member) => throw new System.NotSupportedException(); } public sealed partial class SetOverTryParsingBase : TryParsingSetBase, IClosedSet { public static readonly SetOverTryParsingBase A = new(); } + public sealed partial class SetWithTryParseByRef : IClosedSet { public static readonly SetWithTryParseByRef A = new(); public static bool TryParse(string? name, ref SetWithTryParseByRef member) => throw new System.NotSupportedException(); } + public abstract class TryParsingByRefSetBase { public static bool TryParse(string? name, bool ignoreCase, ref TSelf member) => throw new System.NotSupportedException(); } + public sealed partial class SetOverTryParsingByRefBase : TryParsingByRefSetBase, IClosedSet { public static readonly SetOverTryParsingByRefBase A = new(); } public abstract class MatchingSetBase { public TResult Match(System.Func only) => only(); } public sealed partial class SetOverMatchingBase : MatchingSetBase, IClosedSet { public static readonly SetOverMatchingBase A = new(); } public abstract class ParsableSetBase : System.IParsable where TSelf : ParsableSetBase diff --git a/test/CodoMetis.TypeKit.Generators.Tests/FabricTests.cs b/test/CodoMetis.TypeKit.Generators.Tests/FabricTests.cs index a288162..b3c1664 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/FabricTests.cs +++ b/test/CodoMetis.TypeKit.Generators.Tests/FabricTests.cs @@ -44,7 +44,8 @@ public void Every_declared_value_object_is_generated(Type type) type.GetInterfaces().ShouldContain(typeof(IValueObject<,>).MakeGenericType(type, underlying)); type.GetProperty("Value", BindingFlags.Public | BindingFlags.Instance).ShouldNotBeNull().PropertyType.ShouldBe(underlying); - type.GetMethod(plain ? "From" : "TryFrom", BindingFlags.Public | BindingFlags.Static).ShouldNotBeNull(); + // By its signature: a value object may declare an overload of it, generic or by reference (#226). + type.GetMethod(plain ? "From" : "TryFrom", 0, BindingFlags.Public | BindingFlags.Static, [underlying]).ShouldNotBeNull(); } /// diff --git a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt index 67b03ee..cb6623e 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt +++ b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt @@ -100,7 +100,7 @@ ProbeArticle ProbeArticleFault Description : String Kind : FaultKind - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -166,7 +166,7 @@ ProbeCode ProbeConcurrencyFault Description : String Kind : FaultKind - Match(Func, Func, Func) : TResult + Match(Func, Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -700,7 +700,7 @@ ProbeIsbn extension static ProbeIsbnExtensions.GetValue(ProbeIsbn) : ProbeIsbnText extension static ProbeIsbnExtensions.ValueOrNull(ProbeIsbn?) : ProbeIsbnText ProbeKeyword - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -719,7 +719,7 @@ ProbeKeyword static TryParse(String, out ProbeKeyword) : Boolean ProbeKindlessFault Kind : FaultKind - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -781,7 +781,7 @@ ProbeLabel extension static ProbeLabelExtensions.GetValue(ProbeLabel) : String extension static ProbeLabelExtensions.ValueOrNull(ProbeLabel) : String ProbeLabelled - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -799,7 +799,7 @@ ProbeLabelled static TryParse(String, Boolean, out ProbeLabelled) : Boolean static TryParse(String, out ProbeLabelled) : Boolean ProbeLevel - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -946,7 +946,7 @@ ProbeName extension static ProbeNameExtensions.GetValue(ProbeName) : String extension static ProbeNameExtensions.ValueOrNull(ProbeName?) : String ProbeOrder.Status - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -966,7 +966,7 @@ ProbeOrder.Status ProbeOrderFault Description : String Kind : FaultKind - Match(Func, Func, Func) : TResult + Match(Func, Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1129,7 +1129,7 @@ ProbePin ProbePriority Label : String Match(Action, Action, Action) : Void - Match(Func, Func, Func) : TResult + Match(Func, Func, Func) : TResult Name : String QualifiedName : String Rank : Int32 @@ -1284,7 +1284,7 @@ ProbeSecret extension static ProbeSecretExtensions.GetValue(ProbeSecret) : String extension static ProbeSecretExtensions.ValueOrNull(ProbeSecret) : String ProbeShipment.Status - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1360,7 +1360,7 @@ ProbeSpan extension static ProbeSpanExtensions.GetValue(ProbeSpan) : ProbeSpanText extension static ProbeSpanExtensions.ValueOrNull(ProbeSpan?) : ProbeSpanText ProbeSplit - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1378,7 +1378,7 @@ ProbeSplit static TryParse(String, Boolean, out ProbeSplit) : Boolean static TryParse(String, out ProbeSplit) : Boolean ProbeStatus - Match(Func, Func, Func) : TResult + Match(Func, Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1396,7 +1396,7 @@ ProbeStatus static TryParse(String, Boolean, out ProbeStatus) : Boolean static TryParse(String, out ProbeStatus) : Boolean ProbeTier - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String Perk : String QualifiedName : String @@ -1670,7 +1670,7 @@ DefaultedVersion extension static DefaultedVersionExtensions.GetValue(DefaultedVersion) : Version extension static DefaultedVersionExtensions.ValueOrNull(DefaultedVersion?) : Version DocumentKind - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1688,7 +1688,7 @@ DocumentKind static TryParse(String, Boolean, out DocumentKind) : Boolean static TryParse(String, out DocumentKind) : Boolean EarlyAllStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1706,7 +1706,7 @@ EarlyAllStatus static TryParse(String, Boolean, out EarlyAllStatus) : Boolean static TryParse(String, out EarlyAllStatus) : Boolean EarlyIgnoreCaseParseStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1724,7 +1724,7 @@ EarlyIgnoreCaseParseStatus static TryParse(String, Boolean, out EarlyIgnoreCaseParseStatus) : Boolean static TryParse(String, out EarlyIgnoreCaseParseStatus) : Boolean EarlyIgnoreCaseTryParseStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1742,7 +1742,7 @@ EarlyIgnoreCaseTryParseStatus static TryParse(String, Boolean, out EarlyIgnoreCaseTryParseStatus) : Boolean static TryParse(String, out EarlyIgnoreCaseTryParseStatus) : Boolean EarlyJsonKeyStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1760,7 +1760,7 @@ EarlyJsonKeyStatus static TryParse(String, Boolean, out EarlyJsonKeyStatus) : Boolean static TryParse(String, out EarlyJsonKeyStatus) : Boolean EarlyJsonStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1778,7 +1778,7 @@ EarlyJsonStatus static TryParse(String, Boolean, out EarlyJsonStatus) : Boolean static TryParse(String, out EarlyJsonStatus) : Boolean EarlyParsableStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1796,7 +1796,7 @@ EarlyParsableStatus static TryParse(String, Boolean, out EarlyParsableStatus) : Boolean static TryParse(String, out EarlyParsableStatus) : Boolean EarlyParseStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1814,7 +1814,7 @@ EarlyParseStatus static TryParse(String, Boolean, out EarlyParseStatus) : Boolean static TryParse(String, out EarlyParseStatus) : Boolean EarlyTryParseStatus - Match(Func) : TResult + Match(Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1831,8 +1831,273 @@ EarlyTryParseStatus static Parse(String, Boolean) : EarlyTryParseStatus static TryParse(String, Boolean, out EarlyTryParseStatus) : Boolean static TryParse(String, out EarlyTryParseStatus) : Boolean +FormatOverloadedByArity + CompareTo(FormatOverloadedByArity) : Int32 + CompareTo(Object) : Int32 + Equals(FormatOverloadedByArity) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested FormatOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested FormatOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : FormatOverloadedByArity + static MaxValue : FormatOverloadedByArity + static MinValue : FormatOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : FormatOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : FormatOverloadedByArity + static Parse(String, IFormatProvider) : FormatOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out FormatOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out FormatOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out FormatOverloadedByArity) : Boolean + static op_Equality(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + static op_GreaterThan(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + static op_Inequality(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + static op_LessThan(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + static op_LessThanOrEqual(FormatOverloadedByArity, FormatOverloadedByArity) : Boolean + extension static FormatOverloadedByArityExtensions.GetValue(FormatOverloadedByArity) : Int32 + extension static FormatOverloadedByArityExtensions.ValueOrNull(FormatOverloadedByArity?) : Int32? +FormatOverloadedByIn + CompareTo(FormatOverloadedByIn) : Int32 + CompareTo(Object) : Int32 + Equals(FormatOverloadedByIn) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + ToString(in String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested FormatOverloadedByInJsonConverter : JsonConverter, IStoredJsonConverterSource + nested FormatOverloadedByInTypeConverter : TypeConverter + new() + static From(Int32) : FormatOverloadedByIn + static MaxValue : FormatOverloadedByIn + static MinValue : FormatOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : FormatOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : FormatOverloadedByIn + static Parse(String, IFormatProvider) : FormatOverloadedByIn + static TryParse(ReadOnlySpan, IFormatProvider, out FormatOverloadedByIn) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out FormatOverloadedByIn) : Boolean + static TryParse(String, IFormatProvider, out FormatOverloadedByIn) : Boolean + static op_Equality(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + static op_GreaterThan(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + static op_GreaterThanOrEqual(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + static op_Inequality(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + static op_LessThan(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + static op_LessThanOrEqual(FormatOverloadedByIn, FormatOverloadedByIn) : Boolean + extension static FormatOverloadedByInExtensions.GetValue(FormatOverloadedByIn) : Int32 + extension static FormatOverloadedByInExtensions.ValueOrNull(FormatOverloadedByIn?) : Int32? +FromOverloadedByArity + CompareTo(FromOverloadedByArity) : Int32 + CompareTo(Object) : Int32 + Equals(FromOverloadedByArity) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested FromOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested FromOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : FromOverloadedByArity + static From(Int32) : FromOverloadedByArity + static MaxValue : FromOverloadedByArity + static MinValue : FromOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByArity + static Parse(String, IFormatProvider) : FromOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out FromOverloadedByArity) : Boolean + static op_Equality(FromOverloadedByArity, FromOverloadedByArity) : Boolean + static op_GreaterThan(FromOverloadedByArity, FromOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(FromOverloadedByArity, FromOverloadedByArity) : Boolean + static op_Inequality(FromOverloadedByArity, FromOverloadedByArity) : Boolean + static op_LessThan(FromOverloadedByArity, FromOverloadedByArity) : Boolean + static op_LessThanOrEqual(FromOverloadedByArity, FromOverloadedByArity) : Boolean + extension static FromOverloadedByArityExtensions.GetValue(FromOverloadedByArity) : Int32 + extension static FromOverloadedByArityExtensions.ValueOrNull(FromOverloadedByArity?) : Int32? +FromOverloadedByIn + CompareTo(FromOverloadedByIn) : Int32 + CompareTo(Object) : Int32 + Equals(FromOverloadedByIn) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested FromOverloadedByInJsonConverter : JsonConverter, IStoredJsonConverterSource + nested FromOverloadedByInTypeConverter : TypeConverter + new() + static From(Int32) : FromOverloadedByIn + static From(in Int32) : FromOverloadedByIn + static MaxValue : FromOverloadedByIn + static MinValue : FromOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByIn + static Parse(String, IFormatProvider) : FromOverloadedByIn + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByIn) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByIn) : Boolean + static TryParse(String, IFormatProvider, out FromOverloadedByIn) : Boolean + static op_Equality(FromOverloadedByIn, FromOverloadedByIn) : Boolean + static op_GreaterThan(FromOverloadedByIn, FromOverloadedByIn) : Boolean + static op_GreaterThanOrEqual(FromOverloadedByIn, FromOverloadedByIn) : Boolean + static op_Inequality(FromOverloadedByIn, FromOverloadedByIn) : Boolean + static op_LessThan(FromOverloadedByIn, FromOverloadedByIn) : Boolean + static op_LessThanOrEqual(FromOverloadedByIn, FromOverloadedByIn) : Boolean + extension static FromOverloadedByInExtensions.GetValue(FromOverloadedByIn) : Int32 + extension static FromOverloadedByInExtensions.ValueOrNull(FromOverloadedByIn?) : Int32? +FromOverloadedByRef + CompareTo(FromOverloadedByRef) : Int32 + CompareTo(Object) : Int32 + Equals(FromOverloadedByRef) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested FromOverloadedByRefJsonConverter : JsonConverter, IStoredJsonConverterSource + nested FromOverloadedByRefTypeConverter : TypeConverter + new() + static From(Int32) : FromOverloadedByRef + static From(ref Int32) : FromOverloadedByRef + static MaxValue : FromOverloadedByRef + static MinValue : FromOverloadedByRef + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByRef + static Parse(ReadOnlySpan, IFormatProvider) : FromOverloadedByRef + static Parse(String, IFormatProvider) : FromOverloadedByRef + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByRef) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out FromOverloadedByRef) : Boolean + static TryParse(String, IFormatProvider, out FromOverloadedByRef) : Boolean + static op_Equality(FromOverloadedByRef, FromOverloadedByRef) : Boolean + static op_GreaterThan(FromOverloadedByRef, FromOverloadedByRef) : Boolean + static op_GreaterThanOrEqual(FromOverloadedByRef, FromOverloadedByRef) : Boolean + static op_Inequality(FromOverloadedByRef, FromOverloadedByRef) : Boolean + static op_LessThan(FromOverloadedByRef, FromOverloadedByRef) : Boolean + static op_LessThanOrEqual(FromOverloadedByRef, FromOverloadedByRef) : Boolean + extension static FromOverloadedByRefExtensions.GetValue(FromOverloadedByRef) : Int32 + extension static FromOverloadedByRefExtensions.ValueOrNull(FromOverloadedByRef?) : Int32? LocalOrder.Stage - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1850,7 +2115,7 @@ LocalOrder.Stage static TryParse(String, Boolean, out LocalOrder.Stage) : Boolean static TryParse(String, out LocalOrder.Stage) : Boolean LocalStatus - Match(Func, Func, Func) : TResult + Match(Func, Func, Func) : TResult Name : String QualifiedName : String ToString() : String @@ -1952,7 +2217,7 @@ MaskedOverALocalRecord extension static MaskedOverALocalRecordExtensions.GetValue(MaskedOverALocalRecord) : String extension static MaskedOverALocalRecordExtensions.ValueOrNull(MaskedOverALocalRecord) : String MaskedSet - Match(Func, Func) : TResult + Match(Func, Func) : TResult Name : String QualifiedName : String attribute CompilerGeneratedAttribute @@ -2084,6 +2349,61 @@ OverADeeperExplicitEqualityRecord static op_LessThanOrEqual(OverADeeperExplicitEqualityRecord, OverADeeperExplicitEqualityRecord) : Boolean extension static OverADeeperExplicitEqualityRecordExtensions.GetValue(OverADeeperExplicitEqualityRecord) : Int32 extension static OverADeeperExplicitEqualityRecordExtensions.ValueOrNull(OverADeeperExplicitEqualityRecord) : Int32? +OverALibraryOverloadingBase + $() : OverALibraryOverloadingBase + CompareTo(Object) : Int32 + CompareTo(OverALibraryOverloadingBase) : Int32 + Equals(Object) : Boolean + Equals(OverALibraryOverloadingBase) : Boolean + Equals(ProbeOverloadingRecord) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IEquatable> + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements IReimplementedEquatable> + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested OverALibraryOverloadingBaseJsonConverter : JsonConverter, IStoredJsonConverterSource + nested OverALibraryOverloadingBaseTypeConverter : TypeConverter + static From(Int32) : OverALibraryOverloadingBase + static MaxValue : OverALibraryOverloadingBase + static MinValue : OverALibraryOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : OverALibraryOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : OverALibraryOverloadingBase + static Parse(String, IFormatProvider) : OverALibraryOverloadingBase + static TryParse(ReadOnlySpan, IFormatProvider, out OverALibraryOverloadingBase) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out OverALibraryOverloadingBase) : Boolean + static TryParse(String, IFormatProvider, out OverALibraryOverloadingBase) : Boolean + static op_Equality(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + static op_GreaterThan(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + static op_GreaterThanOrEqual(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + static op_Inequality(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + static op_LessThan(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + static op_LessThanOrEqual(OverALibraryOverloadingBase, OverALibraryOverloadingBase) : Boolean + extension static OverALibraryOverloadingBaseExtensions.GetValue(OverALibraryOverloadingBase) : Int32 + extension static OverALibraryOverloadingBaseExtensions.ValueOrNull(OverALibraryOverloadingBase) : Int32? OverALibraryRecord $() : OverALibraryRecord CompareTo(Object) : Int32 @@ -2345,6 +2665,61 @@ OverAnIdentityRecord static op_LessThanOrEqual(OverAnIdentityRecord, OverAnIdentityRecord) : Boolean extension static OverAnIdentityRecordExtensions.GetValue(OverAnIdentityRecord) : Int32 extension static OverAnIdentityRecordExtensions.ValueOrNull(OverAnIdentityRecord) : Int32? +OverAnOverloadingBase + $() : OverAnOverloadingBase + CompareTo(Object) : Int32 + CompareTo(OverAnOverloadingBase) : Int32 + Equals(Object) : Boolean + Equals(OverAnOverloadingBase) : Boolean + Equals(OverloadingBase) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IEquatable> + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements IReimplementedEquatable> + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested OverAnOverloadingBaseJsonConverter : JsonConverter, IStoredJsonConverterSource + nested OverAnOverloadingBaseTypeConverter : TypeConverter + static From(Int32) : OverAnOverloadingBase + static MaxValue : OverAnOverloadingBase + static MinValue : OverAnOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : OverAnOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : OverAnOverloadingBase + static Parse(String, IFormatProvider) : OverAnOverloadingBase + static TryParse(ReadOnlySpan, IFormatProvider, out OverAnOverloadingBase) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out OverAnOverloadingBase) : Boolean + static TryParse(String, IFormatProvider, out OverAnOverloadingBase) : Boolean + static op_Equality(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + static op_GreaterThan(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + static op_GreaterThanOrEqual(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + static op_Inequality(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + static op_LessThan(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + static op_LessThanOrEqual(OverAnOverloadingBase, OverAnOverloadingBase) : Boolean + extension static OverAnOverloadingBaseExtensions.GetValue(OverAnOverloadingBase) : Int32 + extension static OverAnOverloadingBaseExtensions.ValueOrNull(OverAnOverloadingBase) : Int32? OverByte CompareTo(Object) : Int32 CompareTo(OverByte) : Int32 @@ -3274,6 +3649,29 @@ OverVersion static op_LessThanOrEqual(OverVersion, OverVersion) : Boolean extension static OverVersionExtensions.GetValue(OverVersion) : Version extension static OverVersionExtensions.ValueOrNull(OverVersion?) : Version +OverloadingSet + Match(Func, Func) : TResult + Name : String + QualifiedName : String + ToString() : String + attribute CompilerGeneratedAttribute + attribute GeneratedClosedSetAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IClosedSet + implements IParsable + nested OverloadingSetJsonConverter : JsonConverter + nested OverloadingSetTypeConverter : TypeConverter + static All : IReadOnlyList + static Parse(String) : OverloadingSet + static Parse(String, Boolean) : OverloadingSet + static Parse(String) : OverloadingSet + static Parse(String, Boolean) : OverloadingSet + static TryParse(String, Boolean, OverloadingSet) : Boolean + static TryParse(String, Boolean, out OverloadingSet) : Boolean + static TryParse(String, OverloadingSet) : Boolean + static TryParse(String, out OverloadingSet) : Boolean + static TryParse(String, out OverloadingSet) : Boolean ParityByte CompareTo(Object) : Int32 CompareTo(ParityByte) : Int32 @@ -3843,6 +4241,130 @@ ParityUShort static op_LessThanOrEqual(ParityUShort, ParityUShort) : Boolean extension static ParityUShortExtensions.GetValue(ParityUShort) : UInt16 extension static ParityUShortExtensions.ValueOrNull(ParityUShort?) : UInt16? +ParseOverloadedByArity + CompareTo(Object) : Int32 + CompareTo(ParseOverloadedByArity) : Int32 + Equals(Object) : Boolean + Equals(ParseOverloadedByArity) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested ParseOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested ParseOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : ParseOverloadedByArity + static MaxValue : ParseOverloadedByArity + static MinValue : ParseOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : ParseOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : ParseOverloadedByArity + static Parse(String, IFormatProvider) : ParseOverloadedByArity + static Parse(String, IFormatProvider) : ParseOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out ParseOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out ParseOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out ParseOverloadedByArity) : Boolean + static op_Equality(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + static op_GreaterThan(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + static op_Inequality(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + static op_LessThan(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + static op_LessThanOrEqual(ParseOverloadedByArity, ParseOverloadedByArity) : Boolean + extension static ParseOverloadedByArityExtensions.GetValue(ParseOverloadedByArity) : Int32 + extension static ParseOverloadedByArityExtensions.ValueOrNull(ParseOverloadedByArity?) : Int32? +ParseOverloadedInARecordClass + $() : ParseOverloadedInARecordClass + CompareTo(Object) : Int32 + CompareTo(ParseOverloadedInARecordClass) : Int32 + Equals(Object) : Boolean + Equals(ParseOverloadedInARecordClass) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested ParseOverloadedInARecordClassJsonConverter : JsonConverter, IStoredJsonConverterSource + nested ParseOverloadedInARecordClassTypeConverter : TypeConverter + static From(Int32) : ParseOverloadedInARecordClass + static MaxValue : ParseOverloadedInARecordClass + static MinValue : ParseOverloadedInARecordClass + static Parse(ReadOnlySpan, IFormatProvider) : ParseOverloadedInARecordClass + static Parse(ReadOnlySpan, IFormatProvider) : ParseOverloadedInARecordClass + static Parse(String, IFormatProvider) : ParseOverloadedInARecordClass + static Parse(String, IFormatProvider) : ParseOverloadedInARecordClass + static TryParse(ReadOnlySpan, IFormatProvider, out ParseOverloadedInARecordClass) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out ParseOverloadedInARecordClass) : Boolean + static TryParse(String, IFormatProvider, out ParseOverloadedInARecordClass) : Boolean + static op_Equality(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + static op_GreaterThan(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + static op_GreaterThanOrEqual(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + static op_Inequality(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + static op_LessThan(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + static op_LessThanOrEqual(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean + extension static ParseOverloadedInARecordClassExtensions.GetValue(ParseOverloadedInARecordClass) : Int32 + extension static ParseOverloadedInARecordClassExtensions.ValueOrNull(ParseOverloadedInARecordClass) : Int32? +SetOverAnOverloadingBase + Match(Func, Func) : TResult + Name : String + QualifiedName : String + ToString() : String + attribute CompilerGeneratedAttribute + attribute GeneratedClosedSetAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IClosedSet + implements IParsable + nested SetOverAnOverloadingBaseJsonConverter : JsonConverter + nested SetOverAnOverloadingBaseTypeConverter : TypeConverter + static All : IReadOnlyList + static Parse(String) : SetOverAnOverloadingBase + static Parse(String, Boolean) : SetOverAnOverloadingBase + static TryParse(String, Boolean, out SetOverAnOverloadingBase) : Boolean + static TryParse(String, out SetOverAnOverloadingBase) : Boolean ShippableStatus Equals(Object) : Boolean Equals(ShippableStatus) : Boolean @@ -3874,6 +4396,60 @@ ShippableStatus static op_Inequality(ShippableStatus, ShippableStatus) : Boolean extension static ShippableStatusExtensions.GetValue(ShippableStatus) : LocalStatus extension static ShippableStatusExtensions.ValueOrNull(ShippableStatus?) : LocalStatus +SpanParseOverloaded + CompareTo(Object) : Int32 + CompareTo(SpanParseOverloaded) : Int32 + Equals(Object) : Boolean + Equals(SpanParseOverloaded) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested SpanParseOverloadedJsonConverter : JsonConverter, IStoredJsonConverterSource + nested SpanParseOverloadedTypeConverter : TypeConverter + new() + static From(Int32) : SpanParseOverloaded + static MaxValue : SpanParseOverloaded + static MinValue : SpanParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : SpanParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : SpanParseOverloaded + static Parse(String, IFormatProvider) : SpanParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : SpanParseOverloaded + static TryParse(ReadOnlySpan, IFormatProvider, out SpanParseOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, SpanParseOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out SpanParseOverloaded) : Boolean + static TryParse(String, IFormatProvider, out SpanParseOverloaded) : Boolean + static op_Equality(SpanParseOverloaded, SpanParseOverloaded) : Boolean + static op_GreaterThan(SpanParseOverloaded, SpanParseOverloaded) : Boolean + static op_GreaterThanOrEqual(SpanParseOverloaded, SpanParseOverloaded) : Boolean + static op_Inequality(SpanParseOverloaded, SpanParseOverloaded) : Boolean + static op_LessThan(SpanParseOverloaded, SpanParseOverloaded) : Boolean + static op_LessThanOrEqual(SpanParseOverloaded, SpanParseOverloaded) : Boolean + extension static SpanParseOverloadedExtensions.GetValue(SpanParseOverloaded) : Int32 + extension static SpanParseOverloadedExtensions.ValueOrNull(SpanParseOverloaded?) : Int32? StageOfOrder Equals(Object) : Boolean Equals(StageOfOrder) : Boolean @@ -4215,3 +4791,218 @@ ThrowingSku static op_Inequality(ThrowingSku, ThrowingSku) : Boolean extension static ThrowingSkuExtensions.GetValue(ThrowingSku) : ProbeSkuText extension static ThrowingSkuExtensions.ValueOrNull(ThrowingSku?) : ProbeSkuText +TryFormatOverloaded + CompareTo(Object) : Int32 + CompareTo(TryFormatOverloaded) : Int32 + Equals(Object) : Boolean + Equals(TryFormatOverloaded) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested TryFormatOverloadedJsonConverter : JsonConverter, IStoredJsonConverterSource + nested TryFormatOverloadedTypeConverter : TypeConverter + new() + static From(Int32) : TryFormatOverloaded + static MaxValue : TryFormatOverloaded + static MinValue : TryFormatOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : TryFormatOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : TryFormatOverloaded + static Parse(String, IFormatProvider) : TryFormatOverloaded + static TryParse(ReadOnlySpan, IFormatProvider, out TryFormatOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out TryFormatOverloaded) : Boolean + static TryParse(String, IFormatProvider, out TryFormatOverloaded) : Boolean + static op_Equality(TryFormatOverloaded, TryFormatOverloaded) : Boolean + static op_GreaterThan(TryFormatOverloaded, TryFormatOverloaded) : Boolean + static op_GreaterThanOrEqual(TryFormatOverloaded, TryFormatOverloaded) : Boolean + static op_Inequality(TryFormatOverloaded, TryFormatOverloaded) : Boolean + static op_LessThan(TryFormatOverloaded, TryFormatOverloaded) : Boolean + static op_LessThanOrEqual(TryFormatOverloaded, TryFormatOverloaded) : Boolean + extension static TryFormatOverloadedExtensions.GetValue(TryFormatOverloaded) : Int32 + extension static TryFormatOverloadedExtensions.ValueOrNull(TryFormatOverloaded?) : Int32? +TryParseOverloadedByArity + CompareTo(Object) : Int32 + CompareTo(TryParseOverloadedByArity) : Int32 + Equals(Object) : Boolean + Equals(TryParseOverloadedByArity) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested TryParseOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested TryParseOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : TryParseOverloadedByArity + static MaxValue : TryParseOverloadedByArity + static MinValue : TryParseOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : TryParseOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : TryParseOverloadedByArity + static Parse(String, IFormatProvider) : TryParseOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out TryParseOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out TryParseOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out TryParseOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out TryParseOverloadedByArity) : Boolean + static op_Equality(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + static op_GreaterThan(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + static op_Inequality(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + static op_LessThan(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + static op_LessThanOrEqual(TryParseOverloadedByArity, TryParseOverloadedByArity) : Boolean + extension static TryParseOverloadedByArityExtensions.GetValue(TryParseOverloadedByArity) : Int32 + extension static TryParseOverloadedByArityExtensions.ValueOrNull(TryParseOverloadedByArity?) : Int32? +TryParseOverloadedByValue + CompareTo(Object) : Int32 + CompareTo(TryParseOverloadedByValue) : Int32 + Equals(Object) : Boolean + Equals(TryParseOverloadedByValue) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested TryParseOverloadedByValueJsonConverter : JsonConverter, IStoredJsonConverterSource + nested TryParseOverloadedByValueTypeConverter : TypeConverter + new() + static From(Int32) : TryParseOverloadedByValue + static MaxValue : TryParseOverloadedByValue + static MinValue : TryParseOverloadedByValue + static Parse(ReadOnlySpan, IFormatProvider) : TryParseOverloadedByValue + static Parse(ReadOnlySpan, IFormatProvider) : TryParseOverloadedByValue + static Parse(String, IFormatProvider) : TryParseOverloadedByValue + static TryParse(ReadOnlySpan, IFormatProvider, out TryParseOverloadedByValue) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out TryParseOverloadedByValue) : Boolean + static TryParse(String, IFormatProvider, TryParseOverloadedByValue) : Boolean + static TryParse(String, IFormatProvider, out TryParseOverloadedByValue) : Boolean + static op_Equality(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + static op_GreaterThan(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + static op_GreaterThanOrEqual(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + static op_Inequality(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + static op_LessThan(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + static op_LessThanOrEqual(TryParseOverloadedByValue, TryParseOverloadedByValue) : Boolean + extension static TryParseOverloadedByValueExtensions.GetValue(TryParseOverloadedByValue) : Int32 + extension static TryParseOverloadedByValueExtensions.ValueOrNull(TryParseOverloadedByValue?) : Int32? +Utf8ParseOverloaded + CompareTo(Object) : Int32 + CompareTo(Utf8ParseOverloaded) : Int32 + Equals(Object) : Boolean + Equals(Utf8ParseOverloaded) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested Utf8ParseOverloadedJsonConverter : JsonConverter, IStoredJsonConverterSource + nested Utf8ParseOverloadedTypeConverter : TypeConverter + new() + static From(Int32) : Utf8ParseOverloaded + static MaxValue : Utf8ParseOverloaded + static MinValue : Utf8ParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : Utf8ParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : Utf8ParseOverloaded + static Parse(String, IFormatProvider) : Utf8ParseOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : Utf8ParseOverloaded + static TryParse(ReadOnlySpan, IFormatProvider, Utf8ParseOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out Utf8ParseOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out Utf8ParseOverloaded) : Boolean + static TryParse(String, IFormatProvider, out Utf8ParseOverloaded) : Boolean + static op_Equality(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + static op_GreaterThan(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + static op_GreaterThanOrEqual(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + static op_Inequality(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + static op_LessThan(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + static op_LessThanOrEqual(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean + extension static Utf8ParseOverloadedExtensions.GetValue(Utf8ParseOverloaded) : Int32 + extension static Utf8ParseOverloadedExtensions.ValueOrNull(Utf8ParseOverloaded?) : Int32? diff --git a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurfaceTests.cs b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurfaceTests.cs index 391ccc8..cac93cc 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurfaceTests.cs +++ b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurfaceTests.cs @@ -104,7 +104,7 @@ private static IEnumerable Members(Type type) yield return $"{Static(property.GetMethod!)}{property.Name} : {Display(property.PropertyType)}"; foreach (var method in type.GetMethods(flags).Where(method => !method.IsSpecialName || method.Name.StartsWith("op_", StringComparison.Ordinal))) - yield return $"{Static(method)}{method.Name}({Parameters(method)}) : {Display(method.ReturnType)}"; + yield return $"{Static(method)}{method.Name}{TypeParameters(method)}({Parameters(method)}) : {Display(method.ReturnType)}"; } /// @@ -116,8 +116,18 @@ private static bool IsDeclared(CustomAttributeData attribute) => private static string Static(MethodBase method) => method.IsStatic ? "static " : ""; + /// + /// A generic method's type parameters, and each parameter's ref kind: a hand-written overload that differs from a + /// generated member only by these sits beside it (#226), and the two read as one line without them. + /// + private static string TypeParameters(MethodInfo method) => + method.IsGenericMethodDefinition ? $"<{string.Join(", ", method.GetGenericArguments().Select(Display))}>" : ""; + private static string Parameters(MethodBase method) => - string.Join(", ", method.GetParameters().Select(parameter => (parameter.IsOut ? "out " : "") + Display(parameter.ParameterType))); + string.Join(", ", method.GetParameters().Select(parameter => RefKind(parameter) + Display(parameter.ParameterType))); + + private static string RefKind(ParameterInfo parameter) => + !parameter.ParameterType.IsByRef ? "" : parameter.IsOut ? "out " : parameter.IsIn ? "in " : "ref "; private static string Display(Type type) { diff --git a/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs b/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs new file mode 100644 index 0000000..96ac9e8 --- /dev/null +++ b/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs @@ -0,0 +1,281 @@ +using System.Text; +using CodoMetis.TypeKit.ClosedSets; +using CodoMetis.TypeKit.Generators.Probes; +using CodoMetis.TypeKit.ValueObjects; + +namespace CodoMetis.TypeKit.Generators.Tests; + +// What a value object or a closed set declares beside a generated member: a method of the same name and +// parameter types that C# still tells apart, by its type parameters or by a parameter's ref kind. Each was +// refused as the generated member written by hand (CMTK1011, #226); each is another method, and the generated +// one sits beside it. A ref kind against out (ref, in), and nullability, are no overload, and stay refused +// (BuildOutcomeTests). Every hand-written overload here throws, so a call that reached one fails. + +/// Picks a hand-written generic overload. +public sealed class OverloadFormat; + +/// A generic From. +public readonly partial record struct FromOverloadedByArity : IValue +{ + /// Hand-written. + public static FromOverloadedByArity From(int value) => throw new NotSupportedException("hand-written"); +} + +/// A From by in. +public readonly partial record struct FromOverloadedByIn : IValue +{ + /// Hand-written. + public static FromOverloadedByIn From(in int value) => throw new NotSupportedException("hand-written"); +} + +/// A From by ref. +public readonly partial record struct FromOverloadedByRef : IValue +{ + /// Hand-written. + public static FromOverloadedByRef From(ref int value) => throw new NotSupportedException("hand-written"); +} + +/// A generic Parse over text, the issue's scenario. +public readonly partial record struct ParseOverloadedByArity : IValue +{ + /// Hand-written. + public static ParseOverloadedByArity Parse(string text, IFormatProvider? provider) where TFormat : class => throw new NotSupportedException("hand-written"); +} + +/// A generic TryParse over text. +public readonly partial record struct TryParseOverloadedByArity : IValue +{ + /// Hand-written. + public static bool TryParse(string? text, IFormatProvider? provider, out TryParseOverloadedByArity result) => throw new NotSupportedException("hand-written"); +} + +/// A TryParse over text whose last parameter is by value. +public readonly partial record struct TryParseOverloadedByValue : IValue +{ + /// Hand-written. + public static bool TryParse(string? text, IFormatProvider? provider, TryParseOverloadedByValue fallback) => throw new NotSupportedException("hand-written"); +} + +/// A generic Parse and a by-value TryParse over a span. +public readonly partial record struct SpanParseOverloaded : IValue +{ + /// Hand-written. + public static SpanParseOverloaded Parse(ReadOnlySpan text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(ReadOnlySpan text, IFormatProvider? provider, SpanParseOverloaded fallback) => throw new NotSupportedException("hand-written"); +} + +/// A generic Parse and a by-value TryParse over UTF-8. +public readonly partial record struct Utf8ParseOverloaded : IValue +{ + /// Hand-written. + public static Utf8ParseOverloaded Parse(ReadOnlySpan text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(ReadOnlySpan text, IFormatProvider? provider, Utf8ParseOverloaded fallback) => throw new NotSupportedException("hand-written"); +} + +/// A generic ToString(string?, IFormatProvider?). +public readonly partial record struct FormatOverloadedByArity : IValue +{ + /// Hand-written. + public string ToString(string? format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); +} + +/// A ToString(string?, IFormatProvider?) whose format is by in. +public readonly partial record struct FormatOverloadedByIn : IValue +{ + /// Hand-written. + public string ToString(in string? format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); +} + +/// A generic TryFormat, and one whose count is by value, for both the generated TryFormats. +public readonly partial record struct TryFormatOverloaded : IValue +{ + /// Hand-written. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public bool TryFormat(Span destination, int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public bool TryFormat(Span destination, int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); +} + +/// A record class with a generic Parse. +public sealed partial record ParseOverloadedInARecordClass : IValue +{ + /// Hand-written. + public static ParseOverloadedInARecordClass Parse(string text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); +} + +/// A base record in this assembly whose methods are overloads of the generated ones. +public abstract record OverloadingBase +{ + /// Hand-written. + public static TSelf From(int value) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static TSelf From(in int value) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static TSelf Parse(string text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(string? text, IFormatProvider? provider, TSelf fallback) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static TSelf Parse(ReadOnlySpan text, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(ReadOnlySpan text, IFormatProvider? provider, TSelf fallback) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public string ToString(string? format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotSupportedException("hand-written"); +} + +/// Over a base record in this assembly with an overload of each generated member. +public sealed partial record OverAnOverloadingBase : OverloadingBase, IValue; + +/// Over a base record in another assembly with overloads of Parse, From and TryParse. +public sealed partial record OverALibraryOverloadingBase : ProbeOverloadingRecord, IValue; + +/// A closed set with a generic Parse of each form, a generic TryParse, and by-value ones. +public sealed partial class OverloadingSet : IClosedSet +{ + /// The first member. + public static readonly OverloadingSet First = new(); + + /// The second member. + public static readonly OverloadingSet Second = new(); + + /// Hand-written. + public static OverloadingSet Parse(string name) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static OverloadingSet Parse(string name, bool ignoreCase) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(string? name, out OverloadingSet member) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(string? name, OverloadingSet fallback) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(string? name, bool ignoreCase, OverloadingSet fallback) => throw new NotSupportedException("hand-written"); +} + +/// A base class of a closed set whose Parse and TryParse are overloads of the generated ones. +public abstract class OverloadingSetBase +{ + /// Hand-written. + public static TSelf Parse(string name) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static bool TryParse(string? name, bool ignoreCase, TSelf fallback) => throw new NotSupportedException("hand-written"); +} + +/// A closed set over a base class with overloads of the generated Parse and TryParse. +public sealed partial class SetOverAnOverloadingBase : OverloadingSetBase, IClosedSet +{ + /// The first member. + public static readonly SetOverAnOverloadingBase First = new(); + + /// The second member. + public static readonly SetOverAnOverloadingBase Second = new(); +} + +/// +/// The generated members beside a hand-written overload of each, on the type, on a base record of this assembly +/// and of another, and on a closed set and its base class (#226). Refusals are build errors and live in +/// . +/// +public sealed class OverloadTests +{ + public static TheoryData, object> Generated => new() + { + { "From(int)", () => FromOverloadedByArity.From(7).Value, 7 }, + { "From(in int)", () => FromOverloadedByIn.From(7).Value, 7 }, + { "From(ref int)", () => FromOverloadedByRef.From(7).Value, 7 }, + { "Parse(string, IFormatProvider?)", () => ParseOverloadedByArity.Parse("7", null).Value, 7 }, + { "TryParse(string?, IFormatProvider?, out T)", () => TryParseOverloadedByArity.TryParse("7", null, out var parsed) ? parsed.Value : -1, 7 }, + { "TryParse(string?, IFormatProvider?, T)", () => TryParseOverloadedByValue.TryParse("7", null, out var parsed) ? parsed.Value : -1, 7 }, + { "Parse(ReadOnlySpan, IFormatProvider?)", () => SpanParseOverloaded.Parse("7".AsSpan(), null).Value, 7 }, + { "TryParse(ReadOnlySpan, IFormatProvider?, T)", () => SpanParseOverloaded.TryParse("7".AsSpan(), null, out var parsed) ? parsed.Value : -1, 7 }, + { "Parse(ReadOnlySpan, IFormatProvider?)", () => Utf8ParseOverloaded.Parse("7"u8, null).Value, 7 }, + { "TryParse(ReadOnlySpan, IFormatProvider?, T)", () => Utf8ParseOverloaded.TryParse("7"u8, null, out var parsed) ? parsed.Value : -1, 7 }, + { "IParsable.Parse beside Parse", () => ParseThroughInterface("7"), ParseOverloadedByArity.From(7) }, + { "ToString(string?, IFormatProvider?)", () => FormatOverloadedByArity.From(7).ToString("D3", null), "007" }, + { "ToString(in string?, IFormatProvider?)", () => FormatOverloadedByIn.From(7).ToString("D3", null), "007" }, + { "interpolation beside ToString(string?, IFormatProvider?)", () => $"{FormatOverloadedByArity.From(7):D3}", "007" }, + { "TryFormat(Span, out int, ...) and TryFormat(Span, int, ...)", () => Format(TryFormatOverloaded.From(7)), "007" }, + { "TryFormat(Span, int, ...)", () => FormatUtf8(TryFormatOverloaded.From(7)), "007" }, + { "a record class's Parse(string, IFormatProvider?)", () => ParseOverloadedInARecordClass.Parse("7", null).Value, 7 }, + { "a base record's From(int) and From(in int)", () => OverAnOverloadingBase.From(7).Value, 7 }, + { "a base record's Parse(string, IFormatProvider?)", () => OverAnOverloadingBase.Parse("7", null).Value, 7 }, + { "a base record's TryParse(string?, IFormatProvider?, T)", () => OverAnOverloadingBase.TryParse("7", null, out var parsed) ? parsed.Value : -1, 7 }, + { "a base record's Parse(ReadOnlySpan, IFormatProvider?)", () => OverAnOverloadingBase.Parse("7".AsSpan(), null).Value, 7 }, + { "a base record's TryParse(ReadOnlySpan, IFormatProvider?, T)", () => OverAnOverloadingBase.TryParse("7"u8, null, out var parsed) ? parsed.Value : -1, 7 }, + { "a base record's ToString(string?, IFormatProvider?)", () => OverAnOverloadingBase.From(7).ToString("D3", null), "007" }, + { "a base record's TryFormat(Span, out int, ...)", () => Format(OverAnOverloadingBase.From(7)), "007" }, + { "another assembly's From(in int)", () => OverALibraryOverloadingBase.From(7).Value, 7 }, + { "another assembly's Parse(string, IFormatProvider?)", () => OverALibraryOverloadingBase.Parse("7", null).Value, 7 }, + { "another assembly's TryParse(string?, IFormatProvider?, T)", () => OverALibraryOverloadingBase.TryParse("7", null, out var parsed) ? parsed.Value : -1, 7 }, + { "a set's Parse(string)", () => OverloadingSet.Parse("Second"), OverloadingSet.Second }, + { "a set's Parse(string, bool)", () => OverloadingSet.Parse("second", ignoreCase: true), OverloadingSet.Second }, + { "a set's TryParse(string?, out T) and TryParse(string?, T)", () => OverloadingSet.TryParse("Second", out var member) ? member : OverloadingSet.First, OverloadingSet.Second }, + { "a set's TryParse(string?, bool, T)", () => OverloadingSet.TryParse("second", ignoreCase: true, out var member) ? member : OverloadingSet.First, OverloadingSet.Second }, + { "a set's IParsable.Parse beside Parse(string)", () => ParseThroughInterface("Second"), OverloadingSet.Second }, + { "a set's base class's Parse(string)", () => SetOverAnOverloadingBase.Parse("Second"), SetOverAnOverloadingBase.Second }, + { "a set's base class's TryParse(string?, bool, T)", () => SetOverAnOverloadingBase.TryParse("second", ignoreCase: true, out var member) ? member : SetOverAnOverloadingBase.First, SetOverAnOverloadingBase.Second }, + }; + + /// + /// Each generated member is there beside the hand-written overload, and a call that names neither type arguments + /// nor a ref kind reaches the generated one. + /// + [Theory] + [MemberData(nameof(Generated))] + public void The_generated_member_sits_beside_a_hand_written_overload(string overload, Func generated, object expected) => + generated().ShouldBe(expected, overload); + + public static TheoryData HandWritten => new() + { + { "From(int)", () => FromOverloadedByArity.From(7) }, + { "From(in int)", () => FromOverloadedByIn.From(in Seven) }, + { "Parse(string, IFormatProvider?)", () => ParseOverloadedByArity.Parse("7", null) }, + { "TryParse(string?, IFormatProvider?, T)", () => TryParseOverloadedByValue.TryParse("7", null, TryParseOverloadedByValue.From(1)) }, + { "ToString(string?, IFormatProvider?)", () => FormatOverloadedByArity.From(7).ToString("D3", null) }, + { "TryFormat(Span, int, ...)", () => TryFormatOverloaded.From(7).TryFormat(new char[8], 0, "", null) }, + { "a base record's Parse(string, IFormatProvider?)", () => OverAnOverloadingBase.Parse("7", null) }, + { "another assembly's From(in int)", () => OverALibraryOverloadingBase.From(in Seven) }, + { "a set's Parse(string)", () => OverloadingSet.Parse("Second") }, + { "a set's TryParse(string?, T)", () => OverloadingSet.TryParse("Second", OverloadingSet.First) }, + }; + + /// The hand-written overload is kept, and a call that names its type arguments or its ref kind reaches it. + [Theory] + [MemberData(nameof(HandWritten))] + public void The_hand_written_overload_is_kept(string overload, Action handWritten) => + Should.Throw(handWritten, overload).Message.ShouldBe("hand-written"); + + private static readonly int Seven = 7; + + private static T ParseThroughInterface(string text) where T : IParsable => T.Parse(text, null); + + private static string Format(T value) where T : ISpanFormattable + { + Span buffer = stackalloc char[16]; + return value.TryFormat(buffer, out var written, "D3", null) ? new string(buffer[..written]) : ""; + } + + private static string FormatUtf8(T value) where T : IUtf8SpanFormattable + { + Span buffer = stackalloc byte[16]; + return value.TryFormat(buffer, out var written, "D3", null) ? Encoding.UTF8.GetString(buffer[..written]) : ""; + } +} diff --git a/test/oracles/claims.json b/test/oracles/claims.json index 7e87aad..7eb3e09 100644 --- a/test/oracles/claims.json +++ b/test/oracles/claims.json @@ -1280,6 +1280,35 @@ "BuildOutcomeTests" ] }, + { + "id": "C22-an-overload-in-a-closed-set", + "source": "src/CodoMetis.TypeKit.Generators/README.md#closed-sets", + "quote": "**An overload of a generated method with another signature**, such as `Parse(int rank)` or a generic `Parse(string name)`, is kept too.", + "claim": "A closed set's hand-written overload of Parse or TryParse with another signature, generic or by value where the generated one is out, is kept beside the generated one, in the set or its base class.", + "oracle": "claim", + "surfaces": [ + "IClosedSet.*" + ], + "heldBy": [ + "OverloadTests", + "BuildOutcomeTests" + ] + }, + { + "id": "C22-an-overload-of-a-generated-member", + "source": "src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members", + "quote": "C# tells two methods apart by their type parameters and by whether a parameter is `ref`, `in` or `out`, so a `Parse(string, IFormatProvider?)`, a `From(in int value)` or a `TryParse` whose last parameter isn't `out` is kept, on the value object or a base record. A `ref` or `in` where the generated member has `out` is the same method to C#, as a different nullability is, so it fails the build like the member itself.", + "claim": "A hand-written overload of a generated member that differs by its type parameters or by a ref kind against a by-value parameter is kept beside the generated member, on the value object or a base record; ref or in against out, or another nullability, fails the build with CMTK1011.", + "oracle": "claim", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*" + ], + "heldBy": [ + "OverloadTests", + "BuildOutcomeTests" + ] + }, { "id": "C22-closed-set-named-as-generated-member", "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", From b699d74fb45e25f40390745bf8dfb0bdc837f7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Gro=C3=9F?= Date: Sat, 31 Oct 2026 08:33:44 +0100 Subject: [PATCH 2/2] fix: a generic or by-reference overload of a seam or a synthesized member is another method The previous commit's catalogue, run over the other checks that find a hand-written member by name and parameters, found the same cause in seven of them: each read a method of any arity and any ref kind. Silent, measured with the check reverted: - IsHandWrittenToString took a generic ToString() for the seam. The value object printed "ToStringOverloadedByArity { Value = a }", what a record prints, and a closed set printed its type name. A base record's was CMTK1011 as an unsealed ToString(). - DeclaresCompareTo took a generic or by-in CompareTo(TSelf) for the ordering seam and marked the ordering [HandWrittenOrdering], which the EF Core satellite refuses to order by, though the ordering was generated. - ValueObjectContractAspect skipped re-implementing a deeper base's explicit IEquatable beside a generic Equals(TBase?), so a HashSet held two value objects holding 42. Refused (CMTK1011, CMTK1008), where the generated member sits beside it: a generic or by-in CompareTo(object), a base record's generic CompareTo, TryFrom(int) or TryFrom(in int) and Revalidate() (InheritedSeams), a generic Equals(TSelf) or GetHashCode() (EqualityDeclaredByHand), a base record's (InheritedEquality, CMTK1023), and a generic PrintMembers. Each check now reads only a method without type parameters whose parameters are all by value (IsByValueAndNotGeneric), as every generated member but TryParse and TryFormat is; those two are MethodsWithSignature's. Input class (GTS): as in the previous commit, over the seams (ToString(), CompareTo(TSelf), TryFrom, Revalidate) and what a record synthesizes or calls (Equals, GetHashCode, PrintMembers, CompareTo(object)), on the type, a base record, two levels up and in a closed set. 19 rows join OverloadTests' 34, 4 the hand-written ones, and 3 check the ordering is not marked hand-written. Reverting the commit refuses 5 of its types; reverting IsHandWrittenToString alone fails the 3 ToString rows, DeclaresCompareTo alone the 2 ordering rows, and the contract aspect's check alone the deeper-base row. Refs #226 Defect-Class: GTS Found-By: VA Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + design/aspects.md | 6 + src/CodoMetis.TypeKit.Generators/README.md | 2 + .../ValueObjectComparableAspect.cs | 5 +- .../ValueObjectContractAspect.cs | 2 +- .../ValueObjectDeclaration.cs | 19 +- .../GeneratedSurface.verified.txt | 550 ++++++++++++++++++ .../OverloadTests.cs | 170 ++++++ test/oracles/claims.json | 15 + 9 files changed, 762 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb41446..acdc62f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ section is the GitHub release's notes. - Generators: a closed set over a base class that declares a member the generators add now fails the build with CMTK1011 naming it, where it failed with a Metalama error that named nothing you wrote: its `Parse`, `TryParse`, `Match` or `All`, and an `IParsable` it implements. A base class's `ToString()` that isn't sealed now fails the build too (CMTK1011), so your build can fail when you upgrade: the generated `ToString()` replaced it without a word. Declare `ToString()` in the set, or seal the base's, which is then kept ([Closed sets](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#closed-sets)). - Generators: `IValueObject`, `IValueObjectMaterializer` or `IPlainValueObject` declared through an interface of yours, such as an `IEntityId : IValueObject`, or by a base record now fails with CMTK1011 naming that interface, where it failed with a Metalama error (LAMA0512) that named nothing you wrote. To constrain generic code, use `IValueObject` itself ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). - Generators: an overload of a generated member that C# tells apart by its type parameters, or by a parameter that is `ref`, `in` or `out` where the generated one's isn't (or the other way round), is now kept beside the generated member, on a value object, a closed set or a base of either, where the build failed with CMTK1011: a `Parse(string, IFormatProvider?)`, a `From(in int)`, a `TryParse` whose last parameter isn't `out` ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). +- Generators: a generic `ToString()`, or a generic or by-`in` `CompareTo(TSelf)`, is no longer taken for the one you may write: a value object printed what a record prints (`Level { Value = 3 }`), a closed set its type name, and the ordering was marked hand-written, so EF Core refused to order by it. A generic or by-reference overload of `TryFrom`, `Revalidate`, `CompareTo(object)`, `Equals`, `GetHashCode` or `PrintMembers` is kept beside the generated member, where the build failed with CMTK1011 or CMTK1008 ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)). ## 2.3.0 — 2026-10-29 diff --git a/design/aspects.md b/design/aspects.md index e4c4048..d03456c 100644 --- a/design/aspects.md +++ b/design/aspects.md @@ -190,6 +190,12 @@ and a `TryParse` whose last parameter is by value were CMTK1011, on the type, a base record and a closed set, though Metalama introduces the generated member beside each (measured 2026-10-31). `ref` or `in` against `out` is no overload in C# (CS0663), and nullability none at all, so both stay CMTK1011. + The other checks by name and parameters, the seams and what a record synthesizes, read only a method without + type parameters whose parameters are all by value (`ValueObjectDeclaration.IsByValueAndNotGeneric`), as every + generated member but `TryParse` and `TryFormat` is: a generic `ToString()` was taken for the seam, so + the value object printed what a record prints and a closed set its type name, a generic or by-`in` + `CompareTo(TSelf)` marked the ordering hand-written, and a generic or by-reference `TryFrom`, `Revalidate`, + `CompareTo(object)`, `Equals`, `GetHashCode` or `PrintMembers` was CMTK1011 or CMTK1008. - **Equality over a base record is generated (decided 2026-10-14, [decision 75](adr/0075-equality-over-base-record-generated.md)).** A derived record's synthesized equality calls the base's, which compares the base's fields and whatever the base declares. A base comparing by reference made two value objects holding 42 unequal diff --git a/src/CodoMetis.TypeKit.Generators/README.md b/src/CodoMetis.TypeKit.Generators/README.md index 90bc280..53f439c 100644 --- a/src/CodoMetis.TypeKit.Generators/README.md +++ b/src/CodoMetis.TypeKit.Generators/README.md @@ -244,6 +244,8 @@ apart by their type parameters and by whether a parameter is `ref`, `in` or `out `Parse(string, IFormatProvider?)`, a `From(in int value)` or a `TryParse` whose last parameter isn't `out` is kept, on the value object or a base record. A `ref` or `in` where the generated member has `out` is the same method to C#, as a different nullability is, so it fails the build like the member itself. +The same goes for the members you may write: a generic `ToString()` or a `CompareTo(in TSelf)` isn't +the one that's kept, so the generated `ToString()` and ordering are still there. Two explicit implementations in an interface are fine, because a value object loses nothing by replacing them. A record's own `==` and `!=` replace an interface's, generated or not. And .NET's diff --git a/src/CodoMetis.TypeKit.Generators/ValueObjectComparableAspect.cs b/src/CodoMetis.TypeKit.Generators/ValueObjectComparableAspect.cs index 4427a63..8f30166 100644 --- a/src/CodoMetis.TypeKit.Generators/ValueObjectComparableAspect.cs +++ b/src/CodoMetis.TypeKit.Generators/ValueObjectComparableAspect.cs @@ -143,7 +143,7 @@ private static IEnumerable HandWrittenComparisonMembers(INamedType targe { foreach (var method in target.Methods) { - if (method.IsExplicitInterfaceImplementation) continue; + if (method.IsExplicitInterfaceImplementation || !ValueObjectDeclaration.IsByValueAndNotGeneric(method)) continue; var isObjectOverload = method is { Name: nameof(IComparable.CompareTo), Parameters: [{ Type.SpecialType: SpecialType.Object }] }; var isOrderingOperator = method.OperatorKind is OperatorKind.LessThan or OperatorKind.GreaterThan @@ -162,7 +162,7 @@ private static IEnumerable HandWrittenComparisonMembers(INamedType targe foreach (var method in type.Methods) { if (method is { IsStatic: false, IsExplicitInterfaceImplementation: false, Name: nameof(IComparable.CompareTo), Parameters: [{ } other] } - && ValueObjectDeclaration.IsHandWritten(method) + && ValueObjectDeclaration.IsByValueAndNotGeneric(method) && ValueObjectDeclaration.IsHandWritten(method) && (other.Type.SpecialType == SpecialType.Object || other.Type.ToNonNullable().Equals(target))) yield return $"{method.ToDisplayString()} in its base type {type.ToDisplayString()}"; } @@ -176,6 +176,7 @@ private static IEnumerable HandWrittenComparisonMembers(INamedType targe /// The seam: a CompareTo(TSelf) the type declares itself, which the generated one then leaves in place. private static bool DeclaresCompareTo(INamedType target) => target.Methods.Any(method => method is { IsImplicitlyDeclared: false, IsExplicitInterfaceImplementation: false, Name: nameof(IComparable.CompareTo) } + && ValueObjectDeclaration.IsByValueAndNotGeneric(method) && method.Parameters is [var other] && other.Type.Equals(target)); diff --git a/src/CodoMetis.TypeKit.Generators/ValueObjectContractAspect.cs b/src/CodoMetis.TypeKit.Generators/ValueObjectContractAspect.cs index c5f440a..ab795e8 100644 --- a/src/CodoMetis.TypeKit.Generators/ValueObjectContractAspect.cs +++ b/src/CodoMetis.TypeKit.Generators/ValueObjectContractAspect.cs @@ -101,7 +101,7 @@ private static void IntroduceEquality(IAspectBuilder builder, INamed if (type.Equals(direct) || !ExplicitlyImplementsEquatableBetween(direct, type, equatable.MakeGenericInstance(type))) continue; // One the value object declares itself implements the interface already, as C# maps it. - if (builder.Target.Methods.Any(method => method is { Name: nameof(Equals), Parameters: [{ } other] } && other.Type.ToNonNullable().Equals(type))) continue; + if (builder.Target.Methods.Any(method => method is { Name: nameof(Equals), Parameters: [{ } other] } && other.Type.ToNonNullable().Equals(type) && ValueObjectDeclaration.IsByValueAndNotGeneric(method))) continue; var hidden = type; builder.IntroduceMethod( diff --git a/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs b/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs index da158d3..a240322 100644 --- a/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs +++ b/src/CodoMetis.TypeKit.Generators/ValueObjectDeclaration.cs @@ -54,7 +54,7 @@ public static bool DeclaresToString(INamedType type) => } private static bool IsHandWrittenToString(IMethod method) => - method is { Name: nameof(ToString), IsStatic: false, IsExplicitInterfaceImplementation: false, Parameters.Count: 0 } && IsHandWritten(method); + method is { Name: nameof(ToString), IsStatic: false, IsExplicitInterfaceImplementation: false, Parameters.Count: 0 } && IsByValueAndNotGeneric(method) && IsHandWritten(method); /// /// A value object and the records it derives from, left out. A struct has @@ -439,7 +439,7 @@ public static IReadOnlyList InheritedSeams(INamedType target, INamedType kind != ValueObjectKind.Validated ? [] : [.. SelfAndBases(target).Skip(1).SelectMany(type => type.Methods - .Where(method => IsHandWritten(method) && !method.IsExplicitInterfaceImplementation + .Where(method => IsHandWritten(method) && !method.IsExplicitInterfaceImplementation && IsByValueAndNotGeneric(method) && (method is { Name: "TryFrom", IsStatic: true, Parameters: [{ } value] } && value.Type.ToNonNullable().Equals(valueType.ToNonNullable()) || method is { Name: "Revalidate", IsStatic: false, Parameters.Count: 0 })) .Select(method => $"{method.ToDisplayString()} in its base type {type.ToDisplayString()}"))]; @@ -513,7 +513,7 @@ public static IReadOnlyList PrintMembersDeclaredByHand(INamedType target return [ .. SelfAndBases(target).SelectMany(type => type.Methods - .Where(method => method is { Name: "PrintMembers", IsStatic: false, Parameters: [{ } builder] } && builder.Type.Equals(stringBuilder) && IsHandWritten(method)) + .Where(method => method is { Name: "PrintMembers", IsStatic: false, Parameters: [{ } builder] } && builder.Type.Equals(stringBuilder) && IsByValueAndNotGeneric(method) && IsHandWritten(method)) .Select(method => Describe(method) + (type.Equals(target) ? "" : $" in its base type {type.ToDisplayString()}"))) ]; } @@ -540,7 +540,7 @@ public static IReadOnlyList EqualityDeclaredByHand(INamedType target) return [ .. target.Methods - .Where(method => method is { IsStatic: false, IsImplicitlyDeclared: false } + .Where(method => method is { IsStatic: false, IsImplicitlyDeclared: false } && IsByValueAndNotGeneric(method) && (method.IsExplicitInterfaceImplementation ? method.ExplicitInterfaceImplementations.Any(implemented => implemented.DeclaringType.Definition.Equals(equatable)) : (method is { Name: nameof(Equals), Parameters: [{ } other] } && ownTypes.Any(type => other.Type.ToNonNullable().Equals(type))) @@ -568,7 +568,7 @@ public static IReadOnlyList InheritedEquality(INamedType target) return [ .. SelfAndBases(target).Skip(1).SelectMany(type => type.Methods - .Where(method => method is { IsStatic: false } && IsHandWritten(method) + .Where(method => method is { IsStatic: false } && IsByValueAndNotGeneric(method) && IsHandWritten(method) && (method.IsExplicitInterfaceImplementation ? method.ExplicitInterfaceImplementations.Any(implemented => implemented.DeclaringType.Definition.Equals(equatable)) : (method is { Name: nameof(Equals), Parameters: [{ } other] } && other.Type.Equals(type)) @@ -649,6 +649,15 @@ internal static string Describe(IMember member) internal static bool IsHandWritten(IMember member) => !member.IsImplicitlyDeclared && !member.Attributes.Any(attribute => attribute.Type.Equals(TypeFactory.GetNamedType(typeof(CompilerGeneratedAttribute)))); + /// + /// A method without type parameters whose parameters are all by value, as every generated method is but + /// TryParse and TryFormat (): C# overloads by arity and by a + /// parameter's ref kind, so a generic CompareTo<T>(object?) or a TryFrom(in int) is another + /// method, which the generated one sits beside, and no seam (#226). + /// + internal static bool IsByValueAndNotGeneric(IMethod method) => + method.TypeParameters.Count == 0 && method.Parameters.All(parameter => parameter.RefKind == RefKind.None); + /// Non-implicit members of with one of , of any kind. private static IEnumerable MembersNamed(INamedType target, params string[] names) => MembersNamed(target, methods: true, names); diff --git a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt index cb6623e..ec5946d 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt +++ b/test/CodoMetis.TypeKit.Generators.Tests/GeneratedSurface.verified.txt @@ -1585,6 +1585,112 @@ ProbeWeekday extension static ProbeWeekdayExtensions.GetValue(ProbeWeekday) : DayOfWeek extension static ProbeWeekdayExtensions.ValueOrNull(ProbeWeekday?) : DayOfWeek? # CodoMetis.TypeKit.Generators.Tests +CompareToOverloadedByArity + CompareTo(CompareToOverloadedByArity) : Int32 + CompareTo(Object) : Int32 + CompareTo(CompareToOverloadedByArity) : Int32 + Equals(CompareToOverloadedByArity) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested CompareToOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested CompareToOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : CompareToOverloadedByArity + static MaxValue : CompareToOverloadedByArity + static MinValue : CompareToOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : CompareToOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : CompareToOverloadedByArity + static Parse(String, IFormatProvider) : CompareToOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out CompareToOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out CompareToOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out CompareToOverloadedByArity) : Boolean + static op_Equality(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + static op_GreaterThan(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + static op_Inequality(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + static op_LessThan(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + static op_LessThanOrEqual(CompareToOverloadedByArity, CompareToOverloadedByArity) : Boolean + extension static CompareToOverloadedByArityExtensions.GetValue(CompareToOverloadedByArity) : Int32 + extension static CompareToOverloadedByArityExtensions.ValueOrNull(CompareToOverloadedByArity?) : Int32? +CompareToOverloadedByIn + CompareTo(CompareToOverloadedByIn) : Int32 + CompareTo(Object) : Int32 + CompareTo(in CompareToOverloadedByIn) : Int32 + Equals(CompareToOverloadedByIn) : Boolean + Equals(Object) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested CompareToOverloadedByInJsonConverter : JsonConverter, IStoredJsonConverterSource + nested CompareToOverloadedByInTypeConverter : TypeConverter + new() + static From(Int32) : CompareToOverloadedByIn + static MaxValue : CompareToOverloadedByIn + static MinValue : CompareToOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : CompareToOverloadedByIn + static Parse(ReadOnlySpan, IFormatProvider) : CompareToOverloadedByIn + static Parse(String, IFormatProvider) : CompareToOverloadedByIn + static TryParse(ReadOnlySpan, IFormatProvider, out CompareToOverloadedByIn) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out CompareToOverloadedByIn) : Boolean + static TryParse(String, IFormatProvider, out CompareToOverloadedByIn) : Boolean + static op_Equality(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + static op_GreaterThan(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + static op_GreaterThanOrEqual(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + static op_Inequality(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + static op_LessThan(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + static op_LessThanOrEqual(CompareToOverloadedByIn, CompareToOverloadedByIn) : Boolean + extension static CompareToOverloadedByInExtensions.GetValue(CompareToOverloadedByIn) : Int32 + extension static CompareToOverloadedByInExtensions.ValueOrNull(CompareToOverloadedByIn?) : Int32? DefaultedAddress Equals(DefaultedAddress) : Boolean Equals(Object) : Boolean @@ -1831,6 +1937,119 @@ EarlyTryParseStatus static Parse(String, Boolean) : EarlyTryParseStatus static TryParse(String, Boolean, out EarlyTryParseStatus) : Boolean static TryParse(String, out EarlyTryParseStatus) : Boolean +EqualityOverloadedByArity + CompareTo(EqualityOverloadedByArity) : Int32 + CompareTo(Object) : Int32 + Equals(EqualityOverloadedByArity) : Boolean + Equals(Object) : Boolean + Equals(EqualityOverloadedByArity) : Boolean + GetHashCode() : Int32 + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested EqualityOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested EqualityOverloadedByArityTypeConverter : TypeConverter + new() + static From(Int32) : EqualityOverloadedByArity + static MaxValue : EqualityOverloadedByArity + static MinValue : EqualityOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : EqualityOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : EqualityOverloadedByArity + static Parse(String, IFormatProvider) : EqualityOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out EqualityOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out EqualityOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out EqualityOverloadedByArity) : Boolean + static op_Equality(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + static op_GreaterThan(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + static op_Inequality(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + static op_LessThan(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + static op_LessThanOrEqual(EqualityOverloadedByArity, EqualityOverloadedByArity) : Boolean + extension static EqualityOverloadedByArityExtensions.GetValue(EqualityOverloadedByArity) : Int32 + extension static EqualityOverloadedByArityExtensions.ValueOrNull(EqualityOverloadedByArity?) : Int32? +EqualsOverloadOverADeeperExplicitEquality + $() : EqualsOverloadOverADeeperExplicitEquality + CompareTo(EqualsOverloadOverADeeperExplicitEquality) : Int32 + CompareTo(Object) : Int32 + Equals(EqualsOverloadOverADeeperExplicitEquality) : Boolean + Equals(LocalBetweenRecord) : Boolean + Equals(LocalExplicitEqualityRecord) : Boolean + Equals(Object) : Boolean + Equals(LocalExplicitEqualityRecord) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IEquatable + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements IReimplementedEquatable + implements IReimplementedEquatable + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested EqualsOverloadOverADeeperExplicitEqualityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested EqualsOverloadOverADeeperExplicitEqualityTypeConverter : TypeConverter + static From(Int32) : EqualsOverloadOverADeeperExplicitEquality + static MaxValue : EqualsOverloadOverADeeperExplicitEquality + static MinValue : EqualsOverloadOverADeeperExplicitEquality + static Parse(ReadOnlySpan, IFormatProvider) : EqualsOverloadOverADeeperExplicitEquality + static Parse(ReadOnlySpan, IFormatProvider) : EqualsOverloadOverADeeperExplicitEquality + static Parse(String, IFormatProvider) : EqualsOverloadOverADeeperExplicitEquality + static TryParse(ReadOnlySpan, IFormatProvider, out EqualsOverloadOverADeeperExplicitEquality) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out EqualsOverloadOverADeeperExplicitEquality) : Boolean + static TryParse(String, IFormatProvider, out EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_Equality(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_GreaterThan(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_GreaterThanOrEqual(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_Inequality(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_LessThan(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + static op_LessThanOrEqual(EqualsOverloadOverADeeperExplicitEquality, EqualsOverloadOverADeeperExplicitEquality) : Boolean + extension static EqualsOverloadOverADeeperExplicitEqualityExtensions.GetValue(EqualsOverloadOverADeeperExplicitEquality) : Int32 + extension static EqualsOverloadOverADeeperExplicitEqualityExtensions.ValueOrNull(EqualsOverloadOverADeeperExplicitEquality) : Int32? FormatOverloadedByArity CompareTo(FormatOverloadedByArity) : Int32 CompareTo(Object) : Int32 @@ -2233,6 +2452,60 @@ MaskedSet static Parse(String, Boolean) : MaskedSet static TryParse(String, Boolean, out MaskedSet) : Boolean static TryParse(String, out MaskedSet) : Boolean +ObjectCompareToOverloaded + CompareTo(Object) : Int32 + CompareTo(ObjectCompareToOverloaded) : Int32 + CompareTo(in Object) : Int32 + CompareTo(Object) : Int32 + Equals(Object) : Boolean + Equals(ObjectCompareToOverloaded) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested ObjectCompareToOverloadedJsonConverter : JsonConverter, IStoredJsonConverterSource + nested ObjectCompareToOverloadedTypeConverter : TypeConverter + new() + static From(Int32) : ObjectCompareToOverloaded + static MaxValue : ObjectCompareToOverloaded + static MinValue : ObjectCompareToOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : ObjectCompareToOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : ObjectCompareToOverloaded + static Parse(String, IFormatProvider) : ObjectCompareToOverloaded + static TryParse(ReadOnlySpan, IFormatProvider, out ObjectCompareToOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out ObjectCompareToOverloaded) : Boolean + static TryParse(String, IFormatProvider, out ObjectCompareToOverloaded) : Boolean + static op_Equality(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + static op_GreaterThan(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + static op_GreaterThanOrEqual(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + static op_Inequality(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + static op_LessThan(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + static op_LessThanOrEqual(ObjectCompareToOverloaded, ObjectCompareToOverloaded) : Boolean + extension static ObjectCompareToOverloadedExtensions.GetValue(ObjectCompareToOverloaded) : Int32 + extension static ObjectCompareToOverloadedExtensions.ValueOrNull(ObjectCompareToOverloaded?) : Int32? OverABetweenExplicitEqualityRecord $() : OverABetweenExplicitEqualityRecord CompareTo(Object) : Int32 @@ -4347,6 +4620,114 @@ ParseOverloadedInARecordClass static op_LessThanOrEqual(ParseOverloadedInARecordClass, ParseOverloadedInARecordClass) : Boolean extension static ParseOverloadedInARecordClassExtensions.GetValue(ParseOverloadedInARecordClass) : Int32 extension static ParseOverloadedInARecordClassExtensions.ValueOrNull(ParseOverloadedInARecordClass) : Int32? +PlainOverASeamOverloadingBase + $() : PlainOverASeamOverloadingBase + CompareTo(Object) : Int32 + CompareTo(PlainOverASeamOverloadingBase) : Int32 + Equals(Object) : Boolean + Equals(PlainOverASeamOverloadingBase) : Boolean + Equals(SeamOverloadingBase) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IEquatable> + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements IReimplementedEquatable> + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested PlainOverASeamOverloadingBaseJsonConverter : JsonConverter, IStoredJsonConverterSource + nested PlainOverASeamOverloadingBaseTypeConverter : TypeConverter + static From(Int32) : PlainOverASeamOverloadingBase + static MaxValue : PlainOverASeamOverloadingBase + static MinValue : PlainOverASeamOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : PlainOverASeamOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : PlainOverASeamOverloadingBase + static Parse(String, IFormatProvider) : PlainOverASeamOverloadingBase + static TryParse(ReadOnlySpan, IFormatProvider, out PlainOverASeamOverloadingBase) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out PlainOverASeamOverloadingBase) : Boolean + static TryParse(String, IFormatProvider, out PlainOverASeamOverloadingBase) : Boolean + static op_Equality(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + static op_GreaterThan(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + static op_GreaterThanOrEqual(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + static op_Inequality(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + static op_LessThan(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + static op_LessThanOrEqual(PlainOverASeamOverloadingBase, PlainOverASeamOverloadingBase) : Boolean + extension static PlainOverASeamOverloadingBaseExtensions.GetValue(PlainOverASeamOverloadingBase) : Int32 + extension static PlainOverASeamOverloadingBaseExtensions.ValueOrNull(PlainOverASeamOverloadingBase) : Int32? +PrintMembersOverloadedByArity + $() : PrintMembersOverloadedByArity + CompareTo(Object) : Int32 + CompareTo(PrintMembersOverloadedByArity) : Int32 + Equals(Object) : Boolean + Equals(PrintMembersOverloadedByArity) : Boolean + GetHashCode() : Int32 + PrintMembers(StringBuilder) : Boolean + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IMinMaxValue + implements IParsable + implements IPlainValueObject + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested PrintMembersOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested PrintMembersOverloadedByArityTypeConverter : TypeConverter + static From(Int32) : PrintMembersOverloadedByArity + static MaxValue : PrintMembersOverloadedByArity + static MinValue : PrintMembersOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : PrintMembersOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : PrintMembersOverloadedByArity + static Parse(String, IFormatProvider) : PrintMembersOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out PrintMembersOverloadedByArity) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out PrintMembersOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out PrintMembersOverloadedByArity) : Boolean + static op_Equality(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + static op_GreaterThan(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + static op_Inequality(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + static op_LessThan(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + static op_LessThanOrEqual(PrintMembersOverloadedByArity, PrintMembersOverloadedByArity) : Boolean + extension static PrintMembersOverloadedByArityExtensions.GetValue(PrintMembersOverloadedByArity) : Int32 + extension static PrintMembersOverloadedByArityExtensions.ValueOrNull(PrintMembersOverloadedByArity) : Int32? SetOverAnOverloadingBase Match(Func, Func) : TResult Name : String @@ -4365,6 +4746,25 @@ SetOverAnOverloadingBase static Parse(String, Boolean) : SetOverAnOverloadingBase static TryParse(String, Boolean, out SetOverAnOverloadingBase) : Boolean static TryParse(String, out SetOverAnOverloadingBase) : Boolean +SetWithAGenericToString + Match(Func) : TResult + Name : String + QualifiedName : String + ToString() : String + ToString() : String + attribute CompilerGeneratedAttribute + attribute GeneratedClosedSetAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IClosedSet + implements IParsable + nested SetWithAGenericToStringJsonConverter : JsonConverter + nested SetWithAGenericToStringTypeConverter : TypeConverter + static All : IReadOnlyList + static Parse(String) : SetWithAGenericToString + static Parse(String, Boolean) : SetWithAGenericToString + static TryParse(String, Boolean, out SetWithAGenericToString) : Boolean + static TryParse(String, out SetWithAGenericToString) : Boolean ShippableStatus Equals(Object) : Boolean Equals(ShippableStatus) : Boolean @@ -4791,6 +5191,49 @@ ThrowingSku static op_Inequality(ThrowingSku, ThrowingSku) : Boolean extension static ThrowingSkuExtensions.GetValue(ThrowingSku) : ProbeSkuText extension static ThrowingSkuExtensions.ValueOrNull(ThrowingSku?) : ProbeSkuText +ToStringOverloadedByArity + CompareTo(Object) : Int32 + CompareTo(ToStringOverloadedByArity) : Int32 + Equals(Object) : Boolean + Equals(ToStringOverloadedByArity) : Boolean + GetHashCode() : Int32 + ToString() : String + ToString(String, IFormatProvider) : String + ToString() : String + Value : String + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IParsable + implements IPlainValueObject + implements ISpanParsable + implements IValue + implements IValueObject + implements IValueObjectMaterializer + nested ToStringOverloadedByArityJsonConverter : JsonConverter, IStoredJsonConverterSource + nested ToStringOverloadedByArityTypeConverter : TypeConverter + new() + static From(String) : ToStringOverloadedByArity + static Parse(ReadOnlySpan, IFormatProvider) : ToStringOverloadedByArity + static Parse(String, IFormatProvider) : ToStringOverloadedByArity + static TryParse(ReadOnlySpan, IFormatProvider, out ToStringOverloadedByArity) : Boolean + static TryParse(String, IFormatProvider, out ToStringOverloadedByArity) : Boolean + static op_Equality(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + static op_GreaterThan(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + static op_GreaterThanOrEqual(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + static op_Inequality(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + static op_LessThan(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + static op_LessThanOrEqual(ToStringOverloadedByArity, ToStringOverloadedByArity) : Boolean + extension static ToStringOverloadedByArityExtensions.GetValue(ToStringOverloadedByArity) : String + extension static ToStringOverloadedByArityExtensions.ValueOrNull(ToStringOverloadedByArity?) : String TryFormatOverloaded CompareTo(Object) : Int32 CompareTo(TryFormatOverloaded) : Int32 @@ -4846,6 +5289,59 @@ TryFormatOverloaded static op_LessThanOrEqual(TryFormatOverloaded, TryFormatOverloaded) : Boolean extension static TryFormatOverloadedExtensions.GetValue(TryFormatOverloaded) : Int32 extension static TryFormatOverloadedExtensions.ValueOrNull(TryFormatOverloaded?) : Int32? +TryFromOverloaded + CompareTo(Object) : Int32 + CompareTo(TryFromOverloaded) : Int32 + Equals(Object) : Boolean + Equals(TryFromOverloaded) : Boolean + GetHashCode() : Int32 + Revalidate() : Result + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable + implements IFormattable + implements IParsable + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValidatedValue + implements IValueObject + implements IValueObjectMaterializer + nested TryFromOverloadedJsonConverter : JsonConverter, IStoredJsonConverterSource + nested TryFromOverloadedTypeConverter : TypeConverter + new() + static Create(Int32) : Result + static FromKnownGood(Int32, String) : TryFromOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : TryFromOverloaded + static Parse(ReadOnlySpan, IFormatProvider) : TryFromOverloaded + static Parse(String, IFormatProvider) : TryFromOverloaded + static TryFrom(Int32) : Option + static TryFrom(in Int32) : Option + static TryFrom(Int32) : Option + static TryParse(ReadOnlySpan, IFormatProvider, out TryFromOverloaded) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out TryFromOverloaded) : Boolean + static TryParse(String, IFormatProvider, out TryFromOverloaded) : Boolean + static op_Equality(TryFromOverloaded, TryFromOverloaded) : Boolean + static op_GreaterThan(TryFromOverloaded, TryFromOverloaded) : Boolean + static op_GreaterThanOrEqual(TryFromOverloaded, TryFromOverloaded) : Boolean + static op_Inequality(TryFromOverloaded, TryFromOverloaded) : Boolean + static op_LessThan(TryFromOverloaded, TryFromOverloaded) : Boolean + static op_LessThanOrEqual(TryFromOverloaded, TryFromOverloaded) : Boolean + extension static TryFromOverloadedExtensions.GetValue(TryFromOverloaded) : Int32 + extension static TryFromOverloadedExtensions.ValueOrNull(TryFromOverloaded?) : Int32? TryParseOverloadedByArity CompareTo(Object) : Int32 CompareTo(TryParseOverloadedByArity) : Int32 @@ -5006,3 +5502,57 @@ Utf8ParseOverloaded static op_LessThanOrEqual(Utf8ParseOverloaded, Utf8ParseOverloaded) : Boolean extension static Utf8ParseOverloadedExtensions.GetValue(Utf8ParseOverloaded) : Int32 extension static Utf8ParseOverloadedExtensions.ValueOrNull(Utf8ParseOverloaded?) : Int32? +ValidatedOverASeamOverloadingBase + $() : ValidatedOverASeamOverloadingBase + CompareTo(Object) : Int32 + CompareTo(ValidatedOverASeamOverloadingBase) : Int32 + Equals(Object) : Boolean + Equals(SeamOverloadingBase) : Boolean + Equals(ValidatedOverASeamOverloadingBase) : Boolean + GetHashCode() : Int32 + Revalidate() : Result + ToString() : String + ToString(String, IFormatProvider) : String + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + TryFormat(Span, out Int32, ReadOnlySpan, IFormatProvider) : Boolean + Value : Int32 + attribute CompilerGeneratedAttribute + attribute GeneratedValueObjectAttribute + attribute JsonConverterAttribute + attribute TypeConverterAttribute + implements IComparable + implements IComparable + implements IComparisonOperators + implements IConvertible + implements IEqualityOperators + implements IEquatable> + implements IEquatable + implements IFormattable + implements IParsable + implements IReimplementedEquatable> + implements ISpanFormattable + implements ISpanParsable + implements IUtf8SpanFormattable + implements IUtf8SpanParsable + implements IValidatedValue + implements IValueObject + implements IValueObjectMaterializer + nested ValidatedOverASeamOverloadingBaseJsonConverter : JsonConverter, IStoredJsonConverterSource + nested ValidatedOverASeamOverloadingBaseTypeConverter : TypeConverter + static Create(Int32) : Result + static FromKnownGood(Int32, String) : ValidatedOverASeamOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : ValidatedOverASeamOverloadingBase + static Parse(ReadOnlySpan, IFormatProvider) : ValidatedOverASeamOverloadingBase + static Parse(String, IFormatProvider) : ValidatedOverASeamOverloadingBase + static TryFrom(Int32) : Option + static TryParse(ReadOnlySpan, IFormatProvider, out ValidatedOverASeamOverloadingBase) : Boolean + static TryParse(ReadOnlySpan, IFormatProvider, out ValidatedOverASeamOverloadingBase) : Boolean + static TryParse(String, IFormatProvider, out ValidatedOverASeamOverloadingBase) : Boolean + static op_Equality(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + static op_GreaterThan(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + static op_GreaterThanOrEqual(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + static op_Inequality(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + static op_LessThan(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + static op_LessThanOrEqual(ValidatedOverASeamOverloadingBase, ValidatedOverASeamOverloadingBase) : Boolean + extension static ValidatedOverASeamOverloadingBaseExtensions.GetValue(ValidatedOverASeamOverloadingBase) : Int32 + extension static ValidatedOverASeamOverloadingBaseExtensions.ValueOrNull(ValidatedOverASeamOverloadingBase) : Int32? diff --git a/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs b/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs index 96ac9e8..29b6cce 100644 --- a/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs +++ b/test/CodoMetis.TypeKit.Generators.Tests/OverloadTests.cs @@ -189,6 +189,140 @@ public sealed partial class SetOverAnOverloadingBase : OverloadingSetBaseA fault for the validated value objects below. +public enum OverloadFault +{ + /// Below zero. + Negative +} + +/// A generic ToString(), which is no seam. +public readonly partial record struct ToStringOverloadedByArity : IValue +{ + /// Hand-written. + public string ToString() => throw new NotSupportedException("hand-written"); +} + +/// A generic CompareTo(TSelf), which is no seam. +public readonly partial record struct CompareToOverloadedByArity : IValue +{ + /// Hand-written. + public int CompareTo(CompareToOverloadedByArity other) => throw new NotSupportedException("hand-written"); +} + +/// A CompareTo(TSelf) by in, which is no seam. +public readonly partial record struct CompareToOverloadedByIn : IValue +{ + /// Hand-written. + public int CompareTo(in CompareToOverloadedByIn other) => throw new NotSupportedException("hand-written"); +} + +/// A generic CompareTo(object?) and one by in. +public readonly partial record struct ObjectCompareToOverloaded : IValue +{ + /// Hand-written. + public int CompareTo(object? other) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public int CompareTo(in object? other) => throw new NotSupportedException("hand-written"); +} + +/// A generic Equals(TSelf) and GetHashCode(), which are not its equality. +public readonly partial record struct EqualityOverloadedByArity : IValue +{ + /// Hand-written. + public bool Equals(EqualityOverloadedByArity other) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public int GetHashCode() => throw new NotSupportedException("hand-written"); +} + +/// A record class with a generic PrintMembers, which its synthesized ToString() never calls. +public sealed partial record PrintMembersOverloadedByArity : IValue +{ + /// Hand-written. + public bool PrintMembers(StringBuilder builder) => throw new NotSupportedException("hand-written"); +} + +/// A generic TryFrom and one by in, beside the generated TryFrom(int). +public readonly partial record struct TryFromOverloaded : IValidatedValue +{ + /// Zero or more. + public static Result Create(int value) => value < 0 ? Result.Error(OverloadFault.Negative) : new TryFromOverloaded(value); + + /// Hand-written. + public static Option TryFrom(int value) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static Option TryFrom(in int value) => throw new NotSupportedException("hand-written"); +} + +/// A base record whose seams, equality and ToString() are overloads of the generated ones. +public abstract record SeamOverloadingBase where TSelf : notnull +{ + /// Hand-written. + public static Option TryFrom(int value) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public static Option TryFrom(in int value) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public Result Revalidate() => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public int CompareTo(object? other) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public int CompareTo(TSelf? other) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public string ToString() => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public bool Equals(SeamOverloadingBase? other) => throw new NotSupportedException("hand-written"); + + /// Hand-written. + public int GetHashCode() => throw new NotSupportedException("hand-written"); +} + +/// A plain value object over a base record whose seams are overloads. +public sealed partial record PlainOverASeamOverloadingBase : SeamOverloadingBase, IValue; + +/// A validated value object over a base record whose TryFrom and Revalidate are overloads. +public sealed partial record ValidatedOverASeamOverloadingBase : SeamOverloadingBase, IValidatedValue +{ + /// Zero or more. + public static Result Create(int value) => value < 0 ? Result.Error(OverloadFault.Negative) : new ValidatedOverASeamOverloadingBase(value); +} + +// CMTK1023 names the base's equality, which the generated one does not call. +#pragma warning disable CMTK1023 +/// +/// Two levels above an explicit IEquatable by reference, with a generic Equals of that base's type: the +/// value object implements the base's interface again all the same, since the generic one implements nothing. +/// +public sealed partial record EqualsOverloadOverADeeperExplicitEquality : LocalBetweenRecord, IValue +{ + /// Hand-written. + public bool Equals(LocalExplicitEqualityRecord? other) => throw new NotSupportedException("hand-written"); +} +#pragma warning restore CMTK1023 + +/// A closed set with a generic ToString(), which is no seam. +public sealed partial class SetWithAGenericToString : IClosedSet +{ + /// The first member. + public static readonly SetWithAGenericToString First = new(); + + /// Hand-written. + public string ToString() => throw new NotSupportedException("hand-written"); +} + /// /// The generated members beside a hand-written overload of each, on the type, on a base record of this assembly /// and of another, and on a closed set and its base class (#226). Refusals are build errors and live in @@ -232,6 +366,25 @@ public sealed class OverloadTests { "a set's IParsable.Parse beside Parse(string)", () => ParseThroughInterface("Second"), OverloadingSet.Second }, { "a set's base class's Parse(string)", () => SetOverAnOverloadingBase.Parse("Second"), SetOverAnOverloadingBase.Second }, { "a set's base class's TryParse(string?, bool, T)", () => SetOverAnOverloadingBase.TryParse("second", ignoreCase: true, out var member) ? member : SetOverAnOverloadingBase.First, SetOverAnOverloadingBase.Second }, + { "ToString() beside ToString()", () => ToStringOverloadedByArity.From("a").ToString(), "a" }, + { "interpolation beside ToString()", () => $"{ToStringOverloadedByArity.From("a")}", "a" }, + { "CompareTo(T) beside CompareTo(T)", () => Math.Sign(CompareToOverloadedByArity.From(1).CompareTo(CompareToOverloadedByArity.From(2))), -1 }, + { "IComparable beside CompareTo(T)", () => Math.Sign(((IComparable)CompareToOverloadedByArity.From(1)).CompareTo(CompareToOverloadedByArity.From(2))), -1 }, + { "CompareTo(T) beside CompareTo(in T)", () => Math.Sign(CompareToOverloadedByIn.From(1).CompareTo(CompareToOverloadedByIn.From(2))), -1 }, + { "IComparable beside CompareTo(in T)", () => Math.Sign(((IComparable)CompareToOverloadedByIn.From(1)).CompareTo(CompareToOverloadedByIn.From(2))), -1 }, + { "CompareTo(object) beside CompareTo(object?) and CompareTo(in object?)", () => Math.Sign(((IComparable)ObjectCompareToOverloaded.From(1)).CompareTo(ObjectCompareToOverloaded.From(2))), -1 }, + { "< beside CompareTo(object?)", () => ObjectCompareToOverloaded.From(1) < ObjectCompareToOverloaded.From(2), true }, + { "Equals(T) beside Equals(T)", () => EqualityOverloadedByArity.From(1).Equals(EqualityOverloadedByArity.From(1)), true }, + { "GetHashCode() beside GetHashCode()", () => EqualityOverloadedByArity.From(1).GetHashCode() == EqualityOverloadedByArity.From(1).GetHashCode(), true }, + { "ToString() beside PrintMembers(StringBuilder)", () => PrintMembersOverloadedByArity.From(1).ToString(), "1" }, + { "TryFrom(int) beside TryFrom(int) and TryFrom(in int)", () => TryFromOverloaded.TryFrom(1).IsSome() && TryFromOverloaded.TryFrom(-1).IsNone(), true }, + { "a base record's TryFrom(int) and TryFrom(in int)", () => ValidatedOverASeamOverloadingBase.TryFrom(1).IsSome() && ValidatedOverASeamOverloadingBase.TryFrom(-1).IsNone(), true }, + { "a base record's Revalidate()", () => ValidatedOverASeamOverloadingBase.FromKnownGood(1).Revalidate().TryGetValue(out _, out _), true }, + { "a base record's CompareTo(object?) and CompareTo(TSelf?)", () => PlainOverASeamOverloadingBase.From(1) < PlainOverASeamOverloadingBase.From(2), true }, + { "a base record's ToString()", () => PlainOverASeamOverloadingBase.From(1).ToString(), "1" }, + { "a base record's Equals(TBase?) and GetHashCode()", () => new HashSet> { PlainOverASeamOverloadingBase.From(1), PlainOverASeamOverloadingBase.From(1) }.Count, 1 }, + { "a deeper base's IEquatable beside Equals(TBase?)", () => new HashSet { EqualsOverloadOverADeeperExplicitEquality.From(42), EqualsOverloadOverADeeperExplicitEquality.From(42) }.Count, 1 }, + { "a set's ToString() beside ToString()", () => $"{SetWithAGenericToString.First}", "First" }, }; /// @@ -255,6 +408,10 @@ public void The_generated_member_sits_beside_a_hand_written_overload(string over { "another assembly's From(in int)", () => OverALibraryOverloadingBase.From(in Seven) }, { "a set's Parse(string)", () => OverloadingSet.Parse("Second") }, { "a set's TryParse(string?, T)", () => OverloadingSet.TryParse("Second", OverloadingSet.First) }, + { "ToString()", () => ToStringOverloadedByArity.From("a").ToString() }, + { "CompareTo(in T)", () => CompareToOverloadedByIn.From(1).CompareTo(in OneByIn) }, + { "TryFrom(int)", () => _ = TryFromOverloaded.TryFrom(1) }, + { "a set's ToString()", () => SetWithAGenericToString.First.ToString() }, }; /// The hand-written overload is kept, and a call that names its type arguments or its ref kind reaches it. @@ -263,8 +420,21 @@ public void The_generated_member_sits_beside_a_hand_written_overload(string over public void The_hand_written_overload_is_kept(string overload, Action handWritten) => Should.Throw(handWritten, overload).Message.ShouldBe("hand-written"); + public static TheoryData NotHandWrittenOrdering => [typeof(CompareToOverloadedByArity), typeof(CompareToOverloadedByIn), typeof(PlainOverASeamOverloadingBase)]; + + /// + /// A generic or by-in CompareTo(TSelf) is no seam, so the ordering is the generated one and is not marked + /// hand-written: the EF Core satellite refuses to order by a column whose value object is marked. + /// + [Theory] + [MemberData(nameof(NotHandWrittenOrdering))] + public void An_overload_of_CompareTo_does_not_mark_the_ordering_hand_written(Type type) => + type.IsDefined(typeof(CodoMetis.TypeKit.CompilerServices.HandWrittenOrderingAttribute), inherit: false).ShouldBeFalse(); + private static readonly int Seven = 7; + private static readonly CompareToOverloadedByIn OneByIn = CompareToOverloadedByIn.From(1); + private static T ParseThroughInterface(string text) where T : IParsable => T.Parse(text, null); private static string Format(T value) where T : ISpanFormattable diff --git a/test/oracles/claims.json b/test/oracles/claims.json index 7eb3e09..119cf03 100644 --- a/test/oracles/claims.json +++ b/test/oracles/claims.json @@ -1309,6 +1309,21 @@ "BuildOutcomeTests" ] }, + { + "id": "C22-an-overload-of-a-seam", + "source": "src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members", + "quote": "The same goes for the members you may write: a generic `ToString()` or a `CompareTo(in TSelf)` isn't the one that's kept, so the generated `ToString()` and ordering are still there.", + "claim": "A generic or by-reference overload of ToString() or CompareTo(TSelf) is no seam: the generated ToString() and ordering are introduced beside it, and the ordering is not marked hand-written.", + "oracle": "claim", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "OverloadTests" + ] + }, { "id": "C22-closed-set-named-as-generated-member", "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors",