From 14f3e0471bdb034b2d4847c47c6fba47914b8fed Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 13:56:21 +0200 Subject: [PATCH 01/19] Add option to generate specialized partition implementation --- .../DiscriminatedUnion.cs | 3 +- .../DiscriminatedUnionGenerator.cs | 2 + .../Emitter.cs | 79 ++++++++++++++++--- ...DiscriminatedUnion.SourceGeneration.csproj | 5 +- .../Parser.cs | 12 ++- .../SourceCodeSnippets.cs | 4 + .../Funcky.DiscriminatedUnion.Test.csproj | 4 +- ...ame=UnionWithPartitionUsage.00.verified.cs | 23 ++++++ ...ame=UnionWithPartitionUsage.01.verified.cs | 59 ++++++++++++++ .../SourceGeneratorTest.cs | 2 + .../Sources/UnionWithPartitionUsage.cs | 29 +++++++ Funcky.DiscriminatedUnion.sln | 7 ++ global.json | 2 +- 13 files changed, 210 insertions(+), 21 deletions(-) create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs index 3258ada..5b85ff5 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs @@ -8,7 +8,8 @@ internal sealed record DiscriminatedUnion( string? Namespace, string MethodVisibility, string MatchResultTypeName, - IReadOnlyList Variants); + IReadOnlyList Variants, + bool GeneratePartitionExtension); internal sealed record DiscriminatedUnionVariant( TypeDeclarationSyntax Type, diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs index c4e2169..51f3a1c 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Funcky.DiscriminatedUnion.SourceGeneration.Emitter; @@ -28,6 +29,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(code, AddSource); } + [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "Disabled for Environment.NewLine for now.")] private static void AddSource(SourceProductionContext context, ImmutableArray code) { if (code.Any()) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index e87e181..1fad4bf 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -1,4 +1,3 @@ -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.CodeDom.Compiler; @@ -18,25 +17,81 @@ public static string EmitDiscriminatedUnion(DiscriminatedUnion discriminatedUnio { WriteNamespace(writer, discriminatedUnion); - WriteParentTypes(writer, discriminatedUnion.ParentTypes); + WriteUnionType(discriminatedUnion, writer); - WriteJsonDerivedTypeAttributes(writer, discriminatedUnion); - writer.WriteLine(FormatPartialTypeDeclaration(discriminatedUnion.Type)); - writer.OpenScope(); - - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)};"); - writer.WriteLine(); - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)};"); - - foreach (var variant in discriminatedUnion.Variants) + if (discriminatedUnion.GeneratePartitionExtension) { - WriteVariant(writer, discriminatedUnion, variant); + writer.WriteLine(); + WritePartitionExtension(discriminatedUnion, writer); } } return stringBuilder.ToString(); } + private static void WriteUnionType(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + { + using var scope = writer.AutoCloseScopes(); + + WriteParentTypes(writer, discriminatedUnion.ParentTypes); + + WriteJsonDerivedTypeAttributes(writer, discriminatedUnion); + writer.WriteLine(FormatPartialTypeDeclaration(discriminatedUnion.Type)); + writer.OpenScope(); + + WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)};"); + writer.WriteLine(); + WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)};"); + + foreach (var variant in discriminatedUnion.Variants) + { + WriteVariant(writer, discriminatedUnion, variant); + } + } + + private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + { + using var scope = writer.AutoCloseScopes(); + + writer.WriteLine($"{discriminatedUnion.MethodVisibility} static class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); + writer.OpenScope(); + + writer.Write("public record struct Partitions("); + var partitionVariants = discriminatedUnion + .Variants + .Select(v => $"System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}"); + writer.Write(string.Join(", ", partitionVariants)); + writer.WriteLine(");"); + + writer.WriteLine(); + + writer.WriteLine($"public static Partitions Partition(this System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); + writer.OpenScope(); + + foreach (var variant in discriminatedUnion.Variants) + { + writer.WriteLine($"var {variant.ParameterName}Items = System.Collections.Immutable.ImmutableList.CreateBuilder<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); + } + + using (writer.AutoCloseScopes()) + { + writer.WriteLine("foreach (var item in source)"); + writer.OpenScope(); + writer.Write("item.Switch("); + + var assignmentVariants = discriminatedUnion + .Variants + .Select(v => $"{v.ParameterName}: {v.ParameterName}Items.Add"); + + writer.Write(string.Join(", ", assignmentVariants)); + + writer.WriteLine(");"); + } + + var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.ToImmutable()"); + writer.WriteLine($"return new({string.Join(", ", items)});"); + } + private static void WriteNamespace(IndentedTextWriter writer, DiscriminatedUnion discriminatedUnion) { if (!string.IsNullOrEmpty(discriminatedUnion.Namespace)) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj index 16fd170..5579c69 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj @@ -6,6 +6,7 @@ enable enable 11.0 + true 1.1.0 @@ -38,8 +39,8 @@ - - + + diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs index f236948..a086318 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs @@ -30,7 +30,7 @@ public static bool IsSyntaxTargetForGeneration(SyntaxNode node) return null; } - var (nonExhaustive, flatten, matchResultType) = ParseAttribute(typeSymbol); + var (nonExhaustive, flatten, matchResultType, generatePartitionExtension) = ParseAttribute(typeSymbol); var isVariant = flatten ? IsVariantOfDiscriminatedUnionFlattened(typeSymbol, semanticModel) : IsVariantOfDiscriminatedUnion(typeSymbol, semanticModel); return new DiscriminatedUnion( @@ -39,6 +39,7 @@ public static bool IsSyntaxTargetForGeneration(SyntaxNode node) Namespace: FormatNamespace(typeSymbol), MatchResultTypeName: matchResultType ?? "TResult", MethodVisibility: nonExhaustive ? "internal" : "public", + GeneratePartitionExtension: generatePartitionExtension, Variants: GetVariantTypeDeclarations(typeDeclaration, isVariant) .Select(GetDiscriminatedUnionVariant(typeDeclaration, semanticModel, GenerateJsonDerivedTypeAttribute(typeSymbol))) .ToList()); @@ -50,7 +51,8 @@ private static DiscriminatedUnionAttributeData ParseAttribute(ITypeSymbol type) var nonExhaustive = attribute.GetNamedArgumentOrDefault(AttributeProperties.NonExhaustive); var flatten = attribute.GetNamedArgumentOrDefault(AttributeProperties.Flatten); var matchResultType = attribute.GetNamedArgumentOrDefault(AttributeProperties.MatchResultTypeName); - return new DiscriminatedUnionAttributeData(nonExhaustive, flatten, matchResultType); + var generatePartitionExtension = attribute.GetNamedArgumentOrDefault(AttributeProperties.GeneratePartitionExtension); + return new DiscriminatedUnionAttributeData(nonExhaustive, flatten, matchResultType, generatePartitionExtension); } private static string? FormatNamespace(INamedTypeSymbol typeSymbol) @@ -119,7 +121,11 @@ private static Func IsDiscriminatedUnionAttribute(Generat => context.SemanticModel.GetSymbolInfo(attribute, cancellationToken).Symbol is IMethodSymbol attributeSymbol && attributeSymbol.ContainingType.ToDisplayString() == AttributeFullName; - private sealed record DiscriminatedUnionAttributeData(bool NonExhaustive, bool Flatten, string? MatchResultType); + private sealed record DiscriminatedUnionAttributeData( + bool NonExhaustive, + bool Flatten, + string? MatchResultType, + bool GeneratePartitionExtension); private sealed class VariantCollectingVisitor : CSharpSyntaxWalker { diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/SourceCodeSnippets.cs b/Funcky.DiscriminatedUnion.SourceGeneration/SourceCodeSnippets.cs index b8839c6..378a87d 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/SourceCodeSnippets.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/SourceCodeSnippets.cs @@ -29,6 +29,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool {{AttributeProperties.Flatten}} { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool {{AttributeProperties.GeneratePartitionExtension}} { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? {{AttributeProperties.MatchResultTypeName}} { get; set; } } @@ -46,6 +49,7 @@ public static class AttributeProperties { public const string NonExhaustive = "NonExhaustive"; public const string Flatten = "Flatten"; + public const string GeneratePartitionExtension = "GeneratePartitionExtension"; public const string MatchResultTypeName = "MatchResultTypeName"; } } diff --git a/Funcky.DiscriminatedUnion.Test/Funcky.DiscriminatedUnion.Test.csproj b/Funcky.DiscriminatedUnion.Test/Funcky.DiscriminatedUnion.Test.csproj index 592d660..211f567 100644 --- a/Funcky.DiscriminatedUnion.Test/Funcky.DiscriminatedUnion.Test.csproj +++ b/Funcky.DiscriminatedUnion.Test/Funcky.DiscriminatedUnion.Test.csproj @@ -1,9 +1,9 @@ - net7.0 + net8.0 enable enable - 11.0 + 12.0 false diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs new file mode 100644 index 0000000..eaa443d --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs @@ -0,0 +1,23 @@ +//HintName: DiscriminatedUnionAttribute.g.cs +// +#nullable enable + +namespace Funcky +{ + [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")] + [global::System.AttributeUsage(global::System.AttributeTargets.Class)] + internal sealed class DiscriminatedUnionAttribute : global::System.Attribute + { + /// Allow only consumers in the same assembly to use the exhaustive Match and Switch methods. + public bool NonExhaustive { get; set; } + + /// Generates exhaustive Match and Switch methods for the entire type hierarchy. + public bool Flatten { get; set; } + + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartition { get; set; } + + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. + public string? MatchResultTypeName { get; set; } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs new file mode 100644 index 0000000..cfdb5f7 --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -0,0 +1,59 @@ +//HintName: DiscriminatedUnionGenerator.g.cs +// +#nullable enable + +namespace Funcky.DiscriminatedUnion.Test.Sources +{ + partial record UnionWithPartitionUsage + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public abstract TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public abstract void Switch(global::System.Action success, global::System.Action warning, global::System.Action error); + + partial record Success + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => success(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => success(this); + } + + partial record Warning + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => warning(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => warning(this); + } + + partial record Error + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => error(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => error(this); + } + } + + public static class UnionWithPartitionUsageEnumerableExtensions + { + public record struct Partitions(System.Collections.Generic.IReadOnlyList success, System.Collections.Generic.IReadOnlyList warning, System.Collections.Generic.IReadOnlyList error); + + public static Partitions Partition(this System.Collections.Generic.IEnumerable source) + { + var successItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + var warningItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + var errorItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + foreach (var item in source) + { + item.Switch(success: successItems.Add, warning: warningItems.Add, error: errorItems.Add); + } + return new(successItems.ToImmutable(), warningItems.ToImmutable(), errorItems.ToImmutable()); + } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs index c1cde5f..f9a1282 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs @@ -20,6 +20,7 @@ public sealed class SourceGeneratorTest [InlineData("DeeplyNestedUnion")] [InlineData("NonExhaustive")] [InlineData("JsonPolymorphic")] + [InlineData("UnionWithPartitionUsage")] public async Task GeneratesExpectedSourceCode(string sourceFileName) => await Verify(sourceFileName); [Fact] @@ -53,6 +54,7 @@ private static CSharpCompilation CreateCompilation(params SyntaxTree[] syntaxTre MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Collections.Immutable.ImmutableList).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Text.Json.JsonSerializer).Assembly.Location), }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs new file mode 100644 index 0000000..8bd1369 --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs @@ -0,0 +1,29 @@ +namespace Funcky.DiscriminatedUnion.Test.Sources; + +[DiscriminatedUnion(GeneratePartitionExtension = true)] +public abstract partial record UnionWithPartitionUsage +{ + public sealed partial record Success : UnionWithPartitionUsage; + + public sealed partial record Warning : UnionWithPartitionUsage; + + public sealed partial record Error : UnionWithPartitionUsage; +} + +public static class UnionWithPartitionUsageTest +{ + public static void Test() + { + UnionWithPartitionUsage[] instances = + [ + new UnionWithPartitionUsage.Success(), + new UnionWithPartitionUsage.Warning(), + new UnionWithPartitionUsage.Error(), + new UnionWithPartitionUsage.Success(), + new UnionWithPartitionUsage.Warning(), + new UnionWithPartitionUsage.Warning(), + ]; + + var (successes, warnings, errors) = instances.Partition(); + } +} diff --git a/Funcky.DiscriminatedUnion.sln b/Funcky.DiscriminatedUnion.sln index 2e812ec..d802bd0 100644 --- a/Funcky.DiscriminatedUnion.sln +++ b/Funcky.DiscriminatedUnion.sln @@ -7,6 +7,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Funcky.DiscriminatedUnion.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Funcky.DiscriminatedUnion.Test", "Funcky.DiscriminatedUnion.Test\Funcky.DiscriminatedUnion.Test.csproj", "{B4C3E53F-75BB-4FD4-AF8B-9F715C423766}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_SolutionItems", "_SolutionItems", "{53A014A1-CA3C-476A-ACC5-83CDF144C7AE}" + ProjectSection(SolutionItems) = preProject + changelog.md = changelog.md + global.json = global.json + readme.md = readme.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/global.json b/global.json index 77c776f..959d01c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100", + "version": "8.0.103", "rollForward": "latestFeature" } } From 704682d2627d1d256d810812790cec6ce8c1a038 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 15:38:04 +0200 Subject: [PATCH 02/19] Replace suppresion with workaround --- .../DiscriminatedUnionGenerator.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs index 51f3a1c..6c6226e 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs @@ -29,13 +29,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(code, AddSource); } - [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "Disabled for Environment.NewLine for now.")] private static void AddSource(SourceProductionContext context, ImmutableArray code) { if (code.Any()) { - var combinedCode = $"{GeneratedFileHeadersSource}{Environment.NewLine}{Environment.NewLine}" + - $"{string.Join(Environment.NewLine, code)}"; + const string newline = """ + + + """; + + var combinedCode = $"{GeneratedFileHeadersSource}{newline}{newline}{string.Join(newline, code)}"; context.AddSource("DiscriminatedUnionGenerator.g.cs", combinedCode); } } From bc192e804cf8eac7ebf8f82e931aed6f0528030f Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 15:49:25 +0200 Subject: [PATCH 03/19] Update verified test cases --- ...eFileName=DeeplyNestedUnion.00.verified.cs | 3 + ...e_sourceFileName=EmptyUnion.00.verified.cs | 3 + ...sourceFileName=GenericUnion.00.verified.cs | 3 + ...rceFileName=JsonPolymorphic.00.verified.cs | 3 + ...me=KeywordsAsParameterNames.00.verified.cs | 3 + ...AndSyntacticallyNestedUnion.00.verified.cs | 3 + ...callyNestedUnionWithFlatten.00.verified.cs | 3 + ...callyNestedUnionWithFlatten.00.verified.cs | 3 + ...ourceFileName=NonExhaustive.00.verified.cs | 3 + ...nNestedInMultipleNamespaces.00.verified.cs | 3 + ...thConflictingResultTypeName.00.verified.cs | 3 + ...ame=UnionWithPartitionUsage.00.verified.cs | 46 +++---- ...ame=UnionWithPartitionUsage.01.verified.cs | 118 +++++++++--------- 13 files changed, 115 insertions(+), 82 deletions(-) diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs index 37cbda7..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs @@ -14,6 +14,9 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartitionExtension { get; set; } + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs index eaa443d..2d56691 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs @@ -1,23 +1,23 @@ -//HintName: DiscriminatedUnionAttribute.g.cs -// -#nullable enable - -namespace Funcky -{ - [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")] - [global::System.AttributeUsage(global::System.AttributeTargets.Class)] - internal sealed class DiscriminatedUnionAttribute : global::System.Attribute - { - /// Allow only consumers in the same assembly to use the exhaustive Match and Switch methods. - public bool NonExhaustive { get; set; } - - /// Generates exhaustive Match and Switch methods for the entire type hierarchy. - public bool Flatten { get; set; } - - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. - public bool GeneratePartition { get; set; } - - /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. - public string? MatchResultTypeName { get; set; } - } -} +//HintName: DiscriminatedUnionAttribute.g.cs +// +#nullable enable + +namespace Funcky +{ + [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")] + [global::System.AttributeUsage(global::System.AttributeTargets.Class)] + internal sealed class DiscriminatedUnionAttribute : global::System.Attribute + { + /// Allow only consumers in the same assembly to use the exhaustive Match and Switch methods. + public bool NonExhaustive { get; set; } + + /// Generates exhaustive Match and Switch methods for the entire type hierarchy. + public bool Flatten { get; set; } + + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + public bool GeneratePartition { get; set; } + + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. + public string? MatchResultTypeName { get; set; } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index cfdb5f7..82ff15a 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -1,59 +1,59 @@ -//HintName: DiscriminatedUnionGenerator.g.cs -// -#nullable enable - -namespace Funcky.DiscriminatedUnion.Test.Sources -{ - partial record UnionWithPartitionUsage - { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public abstract TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error); - - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public abstract void Switch(global::System.Action success, global::System.Action warning, global::System.Action error); - - partial record Success - { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => success(this); - - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => success(this); - } - - partial record Warning - { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => warning(this); - - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => warning(this); - } - - partial record Error - { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => error(this); - - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] - public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => error(this); - } - } - - public static class UnionWithPartitionUsageEnumerableExtensions - { - public record struct Partitions(System.Collections.Generic.IReadOnlyList success, System.Collections.Generic.IReadOnlyList warning, System.Collections.Generic.IReadOnlyList error); - - public static Partitions Partition(this System.Collections.Generic.IEnumerable source) - { - var successItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); - var warningItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); - var errorItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); - foreach (var item in source) - { - item.Switch(success: successItems.Add, warning: warningItems.Add, error: errorItems.Add); - } - return new(successItems.ToImmutable(), warningItems.ToImmutable(), errorItems.ToImmutable()); - } - } -} +//HintName: DiscriminatedUnionGenerator.g.cs +// +#nullable enable + +namespace Funcky.DiscriminatedUnion.Test.Sources +{ + partial record UnionWithPartitionUsage + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public abstract TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public abstract void Switch(global::System.Action success, global::System.Action warning, global::System.Action error); + + partial record Success + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => success(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => success(this); + } + + partial record Warning + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => warning(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => warning(this); + } + + partial record Error + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => error(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => error(this); + } + } + + public static class UnionWithPartitionUsageEnumerableExtensions + { + public record struct Partitions(System.Collections.Generic.IReadOnlyList success, System.Collections.Generic.IReadOnlyList warning, System.Collections.Generic.IReadOnlyList error); + + public static Partitions Partition(this System.Collections.Generic.IEnumerable source) + { + var successItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + var warningItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + var errorItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + foreach (var item in source) + { + item.Switch(success: successItems.Add, warning: warningItems.Add, error: errorItems.Add); + } + return new(successItems.ToImmutable(), warningItems.ToImmutable(), errorItems.ToImmutable()); + } + } +} From 5d6e55bc89081ce3f09df0d5ea946ae8ac9bbe6e Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 15:55:22 +0200 Subject: [PATCH 04/19] Fix test --- ...Code_sourceFileName=UnionWithPartitionUsage.00.verified.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs index 2d56691..12ef854 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs @@ -1,4 +1,4 @@ -//HintName: DiscriminatedUnionAttribute.g.cs +//HintName: DiscriminatedUnionAttribute.g.cs // #nullable enable @@ -15,7 +15,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute public bool Flatten { get; set; } /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. - public bool GeneratePartition { get; set; } + public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. public string? MatchResultTypeName { get; set; } From b1456371f0640473ef18f78865265a9204c17ddb Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 16:01:25 +0200 Subject: [PATCH 05/19] Fix tests --- ...ame=UnionWithPartitionUsage.01.verified.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index 82ff15a..774e4b4 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -1,4 +1,4 @@ -//HintName: DiscriminatedUnionGenerator.g.cs +//HintName: DiscriminatedUnionGenerator.g.cs // #nullable enable @@ -8,42 +8,42 @@ partial record UnionWithPartitionUsage { [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public abstract TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error); - + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public abstract void Switch(global::System.Action success, global::System.Action warning, global::System.Action error); - + partial record Success { [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => success(this); - + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => success(this); } - + partial record Warning { [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => warning(this); - + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => warning(this); } - + partial record Error { [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => error(this); - + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => error(this); } } - + public static class UnionWithPartitionUsageEnumerableExtensions { public record struct Partitions(System.Collections.Generic.IReadOnlyList success, System.Collections.Generic.IReadOnlyList warning, System.Collections.Generic.IReadOnlyList error); - + public static Partitions Partition(this System.Collections.Generic.IEnumerable source) { var successItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); From fb2c539f523623dbc21a2a03fd5deccef90be422 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 16:04:47 +0200 Subject: [PATCH 06/19] Bump version, update changelog --- .../Funcky.DiscriminatedUnion.SourceGeneration.csproj | 2 +- changelog.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj index 5579c69..dae5c4d 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj @@ -9,7 +9,7 @@ true - 1.1.0 + 1.2.0 Funcky.DiscriminatedUnion Polyadic MIT OR Apache-2.0 diff --git a/changelog.md b/changelog.md index 28f6358..2fdb880 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,7 @@ # Changelog +## 1.2.0 +* Add an the `GeneratePartitionExtension` option to enable generation of a specialized `Partition` method. + ## 1.1.0 * Add support for generating `[JsonDerivedType]` attributes. From a47b8055216b8af6e69007e8070266b99313bc78 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 16:40:00 +0200 Subject: [PATCH 07/19] Fix tests --- ...eFileName=DeeplyNestedUnion.01.verified.cs | 8 ++-- ...e_sourceFileName=EmptyUnion.01.verified.cs | 4 +- ...sourceFileName=GenericUnion.01.verified.cs | 12 +++--- ...rceFileName=JsonPolymorphic.01.verified.cs | 40 +++++++++---------- ...me=KeywordsAsParameterNames.01.verified.cs | 12 +++--- ...AndSyntacticallyNestedUnion.01.verified.cs | 24 +++++------ ...callyNestedUnionWithFlatten.01.verified.cs | 12 +++--- ...callyNestedUnionWithFlatten.01.verified.cs | 12 +++--- ...ourceFileName=NonExhaustive.01.verified.cs | 12 +++--- ...nNestedInMultipleNamespaces.01.verified.cs | 8 ++-- ...thConflictingResultTypeName.01.verified.cs | 8 ++-- ...ame=UnionWithPartitionUsage.01.verified.cs | 16 ++++---- 12 files changed, 84 insertions(+), 84 deletions(-) diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.01.verified.cs index 4e75c79..3d937ab 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.01.verified.cs @@ -14,18 +14,18 @@ partial class StaticClass { partial record NestedUnion { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func variant); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action variant); partial record Variant { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func variant) => variant(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action variant) => variant(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.01.verified.cs index ae456ec..6122bc4 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.01.verified.cs @@ -4,9 +4,9 @@ partial record EmptyUnion { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(); } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.01.verified.cs index 165fd82..12e0220 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.01.verified.cs @@ -6,27 +6,27 @@ namespace Funcky.DiscriminatedUnion.Test { partial record Result where T : notnull { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal abstract TResult Match(global::System.Func ok, global::System.Func error); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal abstract void Switch(global::System.Action ok, global::System.Action error); partial record Ok { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override TResult Match(global::System.Func ok, global::System.Func error) => ok(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override void Switch(global::System.Action ok, global::System.Action error) => ok(this); } partial record Error { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override TResult Match(global::System.Func ok, global::System.Func error) => error(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override void Switch(global::System.Action ok, global::System.Action error) => error(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.01.verified.cs index e82aa26..6138e1e 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.01.verified.cs @@ -6,27 +6,27 @@ [global::System.Text.Json.Serialization.JsonDerivedType(typeof(global::Result.Error), "Error")] partial record Result { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func ok, global::System.Func error); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action ok, global::System.Action error); partial record Ok { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func ok, global::System.Func error) => ok(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action ok, global::System.Action error) => ok(this); } partial record Error { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func ok, global::System.Func error) => error(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action ok, global::System.Action error) => error(this); } } @@ -39,27 +39,27 @@ partial class Nesting2 [global::System.Text.Json.Serialization.JsonDerivedType(typeof(global::Nesting1<, , >.Nesting2<>.Result<>.Error), "Error")] partial record Result { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func ok, global::System.Func error); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action ok, global::System.Action error); partial record Ok { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func ok, global::System.Func error) => ok(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action ok, global::System.Action error) => ok(this); } partial record Error { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func ok, global::System.Func error) => error(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action ok, global::System.Action error) => error(this); } } @@ -69,36 +69,36 @@ partial record Error [global::System.Text.Json.Serialization.JsonDerivedType(typeof(global::Shape.EquilateralTriangle), "EquilateralTriangle")] partial record Shape { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func rectangle, global::System.Func circle, global::System.Func equilateralTriangle); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action rectangle, global::System.Action circle, global::System.Action equilateralTriangle); partial record Rectangle { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func rectangle, global::System.Func circle, global::System.Func equilateralTriangle) => rectangle(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action rectangle, global::System.Action circle, global::System.Action equilateralTriangle) => rectangle(this); } partial record Circle { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func rectangle, global::System.Func circle, global::System.Func equilateralTriangle) => circle(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action rectangle, global::System.Action circle, global::System.Action equilateralTriangle) => circle(this); } partial record EquilateralTriangle { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func rectangle, global::System.Func circle, global::System.Func equilateralTriangle) => equilateralTriangle(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action rectangle, global::System.Action circle, global::System.Action equilateralTriangle) => equilateralTriangle(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.01.verified.cs index 2efd68c..836a0b7 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.01.verified.cs @@ -6,27 +6,27 @@ namespace Funcky.DiscriminatedUnion.Test { partial record Bool { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func @true, global::System.Func @false); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action @true, global::System.Action @false); partial record True { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func @true, global::System.Func @false) => @true(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action @true, global::System.Action @false) => @true(this); } partial record False { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func @true, global::System.Func @false) => @false(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action @true, global::System.Action @false) => @false(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.01.verified.cs index 7fb5f33..c5e5703 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.01.verified.cs @@ -6,27 +6,27 @@ namespace Funcky.DiscriminatedUnion.Test { partial record SyntaxNode { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func keyword, global::System.Func literal); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action keyword, global::System.Action literal); partial record Keyword { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func literal) => keyword(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action literal) => keyword(this); } partial record Literal { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func literal) => literal(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action literal) => literal(this); } } @@ -38,27 +38,27 @@ partial record SyntaxNode { partial record Literal { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func integer, global::System.Func @string); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action integer, global::System.Action @string); partial record Integer { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func integer, global::System.Func @string) => integer(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action integer, global::System.Action @string) => integer(this); } partial record String { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func integer, global::System.Func @string) => @string(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action integer, global::System.Action @string) => @string(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.01.verified.cs index 2abe511..6d4ca15 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.01.verified.cs @@ -6,18 +6,18 @@ namespace Funcky.DiscriminatedUnion.Test { partial record SyntaxNodeFlattened { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func keyword, global::System.Func integer); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action keyword, global::System.Action integer); partial record Keyword { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func integer) => keyword(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action integer) => keyword(this); } @@ -27,10 +27,10 @@ partial record Number { partial record Integer { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func integer) => integer(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action integer) => integer(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.01.verified.cs index dbe5dfe..0ea2132 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.01.verified.cs @@ -6,27 +6,27 @@ namespace Funcky.DiscriminatedUnion.Test { partial record SyntaxNodeFlattened { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func keyword, global::System.Func integer); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action keyword, global::System.Action integer); partial record Keyword { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func integer) => keyword(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action integer) => keyword(this); } partial record Integer { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func keyword, global::System.Func integer) => integer(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action keyword, global::System.Action integer) => integer(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.01.verified.cs index 165fd82..12e0220 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.01.verified.cs @@ -6,27 +6,27 @@ namespace Funcky.DiscriminatedUnion.Test { partial record Result where T : notnull { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal abstract TResult Match(global::System.Func ok, global::System.Func error); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal abstract void Switch(global::System.Action ok, global::System.Action error); partial record Ok { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override TResult Match(global::System.Func ok, global::System.Func error) => ok(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override void Switch(global::System.Action ok, global::System.Action error) => ok(this); } partial record Error { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override TResult Match(global::System.Func ok, global::System.Func error) => error(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] internal override void Switch(global::System.Action ok, global::System.Action error) => error(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.01.verified.cs index b8193a6..31b732f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.01.verified.cs @@ -6,18 +6,18 @@ namespace Foo.Bar { partial record NestedUnion { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func variant); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action variant); partial record Variant { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func variant) => variant(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action variant) => variant(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.01.verified.cs index e44849b..6ba348d 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.01.verified.cs @@ -4,18 +4,18 @@ partial record UnionWithConflictingGenericType { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TMatchResult Match(global::System.Func variant); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action variant); partial record Variant { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TMatchResult Match(global::System.Func variant) => variant(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action variant) => variant(this); } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index 774e4b4..b371645 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -6,36 +6,36 @@ namespace Funcky.DiscriminatedUnion.Test.Sources { partial record UnionWithPartitionUsage { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public abstract void Switch(global::System.Action success, global::System.Action warning, global::System.Action error); partial record Success { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => success(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => success(this); } partial record Warning { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => warning(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => warning(this); } partial record Error { - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override TResult Match(global::System.Func success, global::System.Func warning, global::System.Func error) => error(this); - [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public override void Switch(global::System.Action success, global::System.Action warning, global::System.Action error) => error(this); } } From 5c20026b98a4be21407cfd2f5d1ffeea4dfed608 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 17 Sep 2024 16:44:49 +0200 Subject: [PATCH 08/19] Remove redundant word in changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 2fdb880..53639a4 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # Changelog ## 1.2.0 -* Add an the `GeneratePartitionExtension` option to enable generation of a specialized `Partition` method. +* Add the `GeneratePartitionExtension` option to enable generation of a specialized `Partition` method. ## 1.1.0 * Add support for generating `[JsonDerivedType]` attributes. From b0e23dd98a6ff97fcf638ea134e6d05bf4920611 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Wed, 18 Sep 2024 10:21:50 +0200 Subject: [PATCH 09/19] Address review --- .../DiscriminatedUnionGenerator.cs | 7 +------ .../Emitter.cs | 19 +++++++++---------- ...DiscriminatedUnion.SourceGeneration.csproj | 4 ++-- .../SourceGeneratorTest.cs | 1 - .../Sources/UnionWithPartitionUsage.cs | 6 +++--- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs index 6c6226e..d15c75a 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs @@ -33,12 +33,7 @@ private static void AddSource(SourceProductionContext context, ImmutableArray $"System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}"); + .Select(v => $"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}"); writer.Write(string.Join(", ", partitionVariants)); - writer.WriteLine(");"); - - writer.WriteLine(); - - writer.WriteLine($"public static Partitions Partition(this System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); + writer.WriteLine(")"); + writer.WriteLine($" Partition(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); writer.OpenScope(); foreach (var variant in discriminatedUnion.Variants) { - writer.WriteLine($"var {variant.ParameterName}Items = System.Collections.Immutable.ImmutableList.CreateBuilder<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); + writer.WriteLine($"var {variant.ParameterName}Items = new global::System.Collections.Generic.List<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); } using (writer.AutoCloseScopes()) @@ -88,7 +87,7 @@ private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnio writer.WriteLine(");"); } - var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.ToImmutable()"); + var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.AsReadOnly()"); writer.WriteLine($"return new({string.Join(", ", items)});"); } diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj index dae5c4d..45936ff 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj @@ -39,8 +39,8 @@ - - + + diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs index f9a1282..8598bcd 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs @@ -54,7 +54,6 @@ private static CSharpCompilation CreateCompilation(params SyntaxTree[] syntaxTre MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location), MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), - MetadataReference.CreateFromFile(typeof(System.Collections.Immutable.ImmutableList).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Text.Json.JsonSerializer).Assembly.Location), }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs index 8bd1369..1255aa7 100644 --- a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs +++ b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs @@ -14,15 +14,15 @@ public static class UnionWithPartitionUsageTest { public static void Test() { - UnionWithPartitionUsage[] instances = - [ + var instances = new UnionWithPartitionUsage[] + { new UnionWithPartitionUsage.Success(), new UnionWithPartitionUsage.Warning(), new UnionWithPartitionUsage.Error(), new UnionWithPartitionUsage.Success(), new UnionWithPartitionUsage.Warning(), new UnionWithPartitionUsage.Warning(), - ]; + }; var (successes, warnings, errors) = instances.Partition(); } From 6744a1d7bd1e73f040e24511c8700b4ff7af8f9d Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Wed, 18 Sep 2024 13:07:58 +0200 Subject: [PATCH 10/19] Update verified files, fix test --- .../DiscriminatedUnionGenerator.cs | 2 +- .../SourceCodeSnippets.cs | 2 +- ...urceFileName=DeeplyNestedUnion.00.verified.cs | 2 +- ...Code_sourceFileName=EmptyUnion.00.verified.cs | 2 +- ...de_sourceFileName=GenericUnion.00.verified.cs | 2 +- ...sourceFileName=JsonPolymorphic.00.verified.cs | 2 +- ...eName=KeywordsAsParameterNames.00.verified.cs | 2 +- ...llyAndSyntacticallyNestedUnion.00.verified.cs | 2 +- ...cticallyNestedUnionWithFlatten.00.verified.cs | 2 +- ...ogicallyNestedUnionWithFlatten.00.verified.cs | 2 +- ...e_sourceFileName=NonExhaustive.00.verified.cs | 2 +- ...nionNestedInMultipleNamespaces.00.verified.cs | 2 +- ...nWithConflictingResultTypeName.00.verified.cs | 2 +- ...leName=UnionWithPartitionUsage.00.verified.cs | 2 +- ...leName=UnionWithPartitionUsage.01.verified.cs | 16 ++++++++-------- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs index d15c75a..07b6fa6 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnionGenerator.cs @@ -33,7 +33,7 @@ private static void AddSource(SourceProductionContext context, ImmutableArrayGenerates exhaustive Match and Switch methods for the entire type hierarchy. public bool {{AttributeProperties.Flatten}} { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool {{AttributeProperties.GeneratePartitionExtension}} { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=DeeplyNestedUnion.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=EmptyUnion.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=GenericUnion.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=JsonPolymorphic.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=KeywordsAsParameterNames.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnion.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyAndSyntacticallyNestedUnionWithFlatten.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=LogicallyNestedUnionWithFlatten.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=NonExhaustive.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionNestedInMultipleNamespaces.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithConflictingResultTypeName.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs index 12ef854..653d24f 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.00.verified.cs @@ -14,7 +14,7 @@ internal sealed class DiscriminatedUnionAttribute : global::System.Attribute /// Generates exhaustive Match and Switch methods for the entire type hierarchy. public bool Flatten { get; set; } - /// If a specialized partition extension method for IEnumerable should be generated. Defaults to false. + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . public bool GeneratePartitionExtension { get; set; } /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index b371645..6f8e050 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -40,20 +40,20 @@ partial record Error } } - public static class UnionWithPartitionUsageEnumerableExtensions + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public static partial class UnionWithPartitionUsageEnumerableExtensions { - public record struct Partitions(System.Collections.Generic.IReadOnlyList success, System.Collections.Generic.IReadOnlyList warning, System.Collections.Generic.IReadOnlyList error); - - public static Partitions Partition(this System.Collections.Generic.IEnumerable source) + public static (global::System.Collections.Generic.IReadOnlyList success, global::System.Collections.Generic.IReadOnlyList warning, global::System.Collections.Generic.IReadOnlyList error) + Partition(this global::System.Collections.Generic.IEnumerable source) { - var successItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); - var warningItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); - var errorItems = System.Collections.Immutable.ImmutableList.CreateBuilder(); + var successItems = new global::System.Collections.Generic.List(); + var warningItems = new global::System.Collections.Generic.List(); + var errorItems = new global::System.Collections.Generic.List(); foreach (var item in source) { item.Switch(success: successItems.Add, warning: warningItems.Add, error: errorItems.Add); } - return new(successItems.ToImmutable(), warningItems.ToImmutable(), errorItems.ToImmutable()); + return new(successItems.AsReadOnly(), warningItems.AsReadOnly(), errorItems.AsReadOnly()); } } } From f22f7129db68348236e04be0f3d49a7c4ddc7abc Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 24 Sep 2024 11:18:03 +0200 Subject: [PATCH 11/19] Write partition with result selector --- .../Emitter.cs | 90 ++++++++++++++++--- ...ame=UnionWithPartitionUsage.01.verified.cs | 15 ++++ .../Sources/UnionWithPartitionUsage.cs | 2 + 3 files changed, 95 insertions(+), 12 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index 3e35ce6..3ffba50 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -22,7 +22,7 @@ public static string EmitDiscriminatedUnion(DiscriminatedUnion discriminatedUnio if (discriminatedUnion.GeneratePartitionExtension) { writer.WriteLine(); - WritePartitionExtension(discriminatedUnion, writer); + WritePartitionExtensions(discriminatedUnion, writer); } } @@ -49,7 +49,7 @@ private static void WriteUnionType(DiscriminatedUnion discriminatedUnion, Indent } } - private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + private static void WritePartitionExtensions(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) { using var scope = writer.AutoCloseScopes(); @@ -57,6 +57,15 @@ private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnio writer.WriteLine($"{discriminatedUnion.MethodVisibility} static partial class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); writer.OpenScope(); + WriteTupleReturningPartitionExtension(discriminatedUnion, writer); + writer.WriteLine(); + WritePartitionWithResultSelector(discriminatedUnion, writer); + } + + private static void WriteTupleReturningPartitionExtension(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + { + using var methodScope = writer.AutoCloseScopes(); + writer.Write($"public static "); writer.Write("("); var partitionVariants = discriminatedUnion @@ -67,6 +76,46 @@ private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnio writer.WriteLine($" Partition(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); writer.OpenScope(); + WritePartitioningIntoLists(discriminatedUnion, writer); + + var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.AsReadOnly()"); + writer.WriteLine($"return new({string.Join(", ", items)});"); + } + + private static void WritePartitionWithResultSelector(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + { + using var methodScope = writer.AutoCloseScopes(); + + writer.Write($"public static TResult Partition<{discriminatedUnion.MatchResultTypeName}>(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source, global::System.Func<"); + + foreach (var variant in discriminatedUnion.Variants) + { + writer.Write("global::System.Collections.Generic.IReadOnlyList<"); + writer.Write(discriminatedUnion.Type.Identifier); + writer.Write("."); + writer.Write(variant.LocalTypeName); + writer.WriteLine(">, "); + } + + writer.WriteLine($"{discriminatedUnion.MatchResultTypeName}> resultSelector)"); + writer.OpenScope(); + + WritePartitioningIntoLists(discriminatedUnion, writer); + + writer.Write("return resultSelector("); + WriteCommaSeparated( + discriminatedUnion.Variants, + (v, w) => + { + w.Write(v.ParameterName); + w.Write("Items.AsReadOnly()"); + }, + writer); + writer.WriteLine(");"); + } + + private static void WritePartitioningIntoLists(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) + { foreach (var variant in discriminatedUnion.Variants) { writer.WriteLine($"var {variant.ParameterName}Items = new global::System.Collections.Generic.List<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); @@ -77,18 +126,18 @@ private static void WritePartitionExtension(DiscriminatedUnion discriminatedUnio writer.WriteLine("foreach (var item in source)"); writer.OpenScope(); writer.Write("item.Switch("); - - var assignmentVariants = discriminatedUnion - .Variants - .Select(v => $"{v.ParameterName}: {v.ParameterName}Items.Add"); - - writer.Write(string.Join(", ", assignmentVariants)); - + WriteCommaSeparated( + discriminatedUnion.Variants, + (v, w) => + { + w.Write(v.ParameterName); + w.Write(": "); + w.Write(v.ParameterName); + w.Write("Items.Add"); + }, + writer); writer.WriteLine(");"); } - - var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.AsReadOnly()"); - writer.WriteLine($"return new({string.Join(", ", items)});"); } private static void WriteNamespace(IndentedTextWriter writer, DiscriminatedUnion discriminatedUnion) @@ -167,4 +216,21 @@ private static string FormatIdentifier(string identifier) private static bool IsIdentifier(string identifier) => SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None; + + // Prevents extra string allocations compared to usages of string.Join before calling the writer. + private static void WriteCommaSeparated(IEnumerable items, Action action, IndentedTextWriter writer) + { + using var enumerator = items.GetEnumerator(); + + if (enumerator.MoveNext()) + { + action(enumerator.Current, writer); + + while (enumerator.MoveNext()) + { + writer.Write(", "); + action(enumerator.Current, writer); + } + } + } } diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index 6f8e050..e4261cd 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -55,5 +55,20 @@ public static (global::System.Collections.Generic.IReadOnlyList(this global::System.Collections.Generic.IEnumerable source, global::System.Func, + global::System.Collections.Generic.IReadOnlyList, + global::System.Collections.Generic.IReadOnlyList, + TResult> resultSelector) + { + var successItems = new global::System.Collections.Generic.List(); + var warningItems = new global::System.Collections.Generic.List(); + var errorItems = new global::System.Collections.Generic.List(); + foreach (var item in source) + { + item.Switch(success: successItems.Add, warning: warningItems.Add, error: errorItems.Add); + } + return resultSelector(successItems.AsReadOnly(), warningItems.AsReadOnly(), errorItems.AsReadOnly()); + } } } diff --git a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs index 1255aa7..9ec66d8 100644 --- a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs +++ b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs @@ -25,5 +25,7 @@ public static void Test() }; var (successes, warnings, errors) = instances.Partition(); + + var warningsAndErrorsCount = instances.Partition(resultSelector: (_, w, e) => w.Count + e.Count); } } From 5a459e168f82ed7a0ba338bdc6bed88d21a00832 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 24 Sep 2024 16:53:25 +0200 Subject: [PATCH 12/19] Refactor and optimize string writing --- .../CollectingInterpolatedStringHandler.cs | 33 +++++++ ...tingInterpolatedStringHandlerExtensions.cs | 53 +++++++++++ .../Emitter.cs | 94 +++++-------------- ...DiscriminatedUnion.SourceGeneration.csproj | 2 +- .../IndentedTextWriterExtensions.cs | 14 +++ ...ame=UnionWithPartitionUsage.01.verified.cs | 10 +- 6 files changed, 130 insertions(+), 76 deletions(-) create mode 100644 Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs create mode 100644 Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs new file mode 100644 index 0000000..494828a --- /dev/null +++ b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs @@ -0,0 +1,33 @@ +using System.Runtime.CompilerServices; + +namespace Funcky.DiscriminatedUnion.SourceGeneration; + +[InterpolatedStringHandler] +public readonly struct CollectingInterpolatedStringHandler +{ + public CollectingInterpolatedStringHandler(int literalLength, int formattedCount) + { + _items = new List(formattedCount * 2); + } + + public CollectingInterpolatedStringHandler(List items) + { + _items = items; + } + + public CollectingInterpolatedStringHandler() + { + _items = new List(); + } + + private readonly List _items; + + public IEnumerable GetItems() => _items; + + public void AppendLiteral(string s) => _items.Add(s); + + public void AppendFormatted(T t) => _items.Add(t); + + public void AppendFormatted(CollectingInterpolatedStringHandler handler) + => _items.AddRange(handler._items); +} diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs new file mode 100644 index 0000000..7f0bb07 --- /dev/null +++ b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs @@ -0,0 +1,53 @@ +namespace Funcky.DiscriminatedUnion.SourceGeneration; + +public static class CollectingInterpolatedStringHandlerExtensions +{ + public static CollectingInterpolatedStringHandler JoinToInterpolation( + this IEnumerable source, + string separator) + { + using var enumerator = source.GetEnumerator(); + + if (!enumerator.MoveNext()) + { + return default; + } + + var result = new CollectingInterpolatedStringHandler(); + + result.AppendFormatted(enumerator.Current); + + while (enumerator.MoveNext()) + { + result.AppendLiteral(separator); + result.AppendFormatted(enumerator.Current); + } + + return result; + } + + public static CollectingInterpolatedStringHandler JoinToInterpolation( + this IEnumerable source, + Func createPart, + string separator) + { + using var enumerator = source.GetEnumerator(); + + if (!enumerator.MoveNext()) + { + return default; + } + + var result = new CollectingInterpolatedStringHandler(); + + result.AppendFormatted(createPart(enumerator.Current)); + + while (enumerator.MoveNext()) + { + result.AppendLiteral(separator); + result.AppendFormatted(createPart(enumerator.Current)); + } + + return result; + } +} diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index 3ffba50..09db2fe 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.CodeDom.Compiler; +using System.Runtime.CompilerServices; using System.Text; using static Funcky.DiscriminatedUnion.SourceGeneration.SourceCodeSnippets; @@ -36,7 +37,7 @@ private static void WriteUnionType(DiscriminatedUnion discriminatedUnion, Indent WriteParentTypes(writer, discriminatedUnion.ParentTypes); WriteJsonDerivedTypeAttributes(writer, discriminatedUnion); - writer.WriteLine(FormatPartialTypeDeclaration(discriminatedUnion.Type)); + writer.WriteLineInterpolated(FormatPartialTypeDeclaration(discriminatedUnion.Type)); writer.OpenScope(); WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)};"); @@ -54,7 +55,7 @@ private static void WritePartitionExtensions(DiscriminatedUnion discriminatedUni using var scope = writer.AutoCloseScopes(); writer.WriteLine(GeneratedCodeAttributeSource); - writer.WriteLine($"{discriminatedUnion.MethodVisibility} static partial class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); + writer.WriteLineInterpolated($"{discriminatedUnion.MethodVisibility} static partial class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); writer.OpenScope(); WriteTupleReturningPartitionExtension(discriminatedUnion, writer); @@ -66,77 +67,51 @@ private static void WriteTupleReturningPartitionExtension(DiscriminatedUnion dis { using var methodScope = writer.AutoCloseScopes(); - writer.Write($"public static "); - writer.Write("("); - var partitionVariants = discriminatedUnion + var namedResultPartitions = discriminatedUnion .Variants - .Select(v => $"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}"); - writer.Write(string.Join(", ", partitionVariants)); - writer.WriteLine(")"); - writer.WriteLine($" Partition(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); + .JoinToInterpolation( + v => $"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}", + ", "); + + writer.WriteLineInterpolated($"public static ({namedResultPartitions}) Partition(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); writer.OpenScope(); WritePartitioningIntoLists(discriminatedUnion, writer); - var items = discriminatedUnion.Variants.Select(v => $"{v.ParameterName}Items.AsReadOnly()"); - writer.WriteLine($"return new({string.Join(", ", items)});"); + writer.WriteLineInterpolated($"return ({discriminatedUnion.Variants.JoinToInterpolation(v => $"{v.ParameterName}Items.AsReadOnly()", ", ")});"); } private static void WritePartitionWithResultSelector(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) { using var methodScope = writer.AutoCloseScopes(); - writer.Write($"public static TResult Partition<{discriminatedUnion.MatchResultTypeName}>(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source, global::System.Func<"); + writer.WriteInterpolated($"public static TResult Partition<{discriminatedUnion.MatchResultTypeName}>(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source, global::System.Func<"); foreach (var variant in discriminatedUnion.Variants) { - writer.Write("global::System.Collections.Generic.IReadOnlyList<"); - writer.Write(discriminatedUnion.Type.Identifier); - writer.Write("."); - writer.Write(variant.LocalTypeName); - writer.WriteLine(">, "); + writer.WriteInterpolated($"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>, "); } - writer.WriteLine($"{discriminatedUnion.MatchResultTypeName}> resultSelector)"); + writer.WriteLineInterpolated($"{discriminatedUnion.MatchResultTypeName}> resultSelector)"); writer.OpenScope(); WritePartitioningIntoLists(discriminatedUnion, writer); - writer.Write("return resultSelector("); - WriteCommaSeparated( - discriminatedUnion.Variants, - (v, w) => - { - w.Write(v.ParameterName); - w.Write("Items.AsReadOnly()"); - }, - writer); - writer.WriteLine(");"); + writer.WriteLineInterpolated($"return resultSelector({discriminatedUnion.Variants.JoinToInterpolation(v => $"{v.ParameterName}Items.AsReadOnly()", ", ")});"); } private static void WritePartitioningIntoLists(DiscriminatedUnion discriminatedUnion, IndentedTextWriter writer) { foreach (var variant in discriminatedUnion.Variants) { - writer.WriteLine($"var {variant.ParameterName}Items = new global::System.Collections.Generic.List<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); + writer.WriteLineInterpolated($"var {variant.ParameterName}Items = new global::System.Collections.Generic.List<{discriminatedUnion.Type.Identifier}.{variant.LocalTypeName}>();"); } using (writer.AutoCloseScopes()) { writer.WriteLine("foreach (var item in source)"); writer.OpenScope(); - writer.Write("item.Switch("); - WriteCommaSeparated( - discriminatedUnion.Variants, - (v, w) => - { - w.Write(v.ParameterName); - w.Write(": "); - w.Write(v.ParameterName); - w.Write("Items.Add"); - }, - writer); - writer.WriteLine(");"); + writer.WriteLineInterpolated($"item.Switch({discriminatedUnion.Variants.JoinToInterpolation(v => $"{v.ParameterName}: {v.ParameterName}Items.Add", ", ")});"); } } @@ -144,7 +119,7 @@ private static void WriteNamespace(IndentedTextWriter writer, DiscriminatedUnion { if (!string.IsNullOrEmpty(discriminatedUnion.Namespace)) { - writer.WriteLine($"namespace {discriminatedUnion.Namespace}"); + writer.WriteLineInterpolated($"namespace {discriminatedUnion.Namespace}"); writer.OpenScope(); } } @@ -153,7 +128,7 @@ private static void WriteParentTypes(IndentedTextWriter writer, IEnumerable {FormatIdentifier(variant.ParameterName)}(this);"); @@ -175,10 +150,10 @@ private static void WriteVariant(IndentedTextWriter writer, DiscriminatedUnion d } } - private static void WriteGeneratedMethod(IndentedTextWriter writer, string method) + private static void WriteGeneratedMethod(IndentedTextWriter writer, CollectingInterpolatedStringHandler method) { writer.WriteLine(GeneratedCodeAttributeSource); - writer.WriteLine(method); + writer.WriteLineInterpolated(method); } private static void WriteJsonDerivedTypeAttributes(IndentedTextWriter writer, DiscriminatedUnion discriminatedUnion) @@ -193,44 +168,27 @@ private static void WriteJsonDerivedTypeAttribute(IndentedTextWriter writer, Dis { if (variant.GenerateJsonDerivedTypeAttribute) { - writer.WriteLine($"[global::System.Text.Json.Serialization.JsonDerivedType(typeof({variant.TypeOfTypeName}), {SyntaxFactory.Literal(variant.JsonDerivedTypeDiscriminator)})]"); + writer.WriteLineInterpolated($"[global::System.Text.Json.Serialization.JsonDerivedType(typeof({variant.TypeOfTypeName}), {SyntaxFactory.Literal(variant.JsonDerivedTypeDiscriminator)})]"); } } - private static string FormatMatchMethodDeclaration(string genericTypeName, IEnumerable variants) + private static CollectingInterpolatedStringHandler FormatMatchMethodDeclaration(string genericTypeName, IEnumerable variants) => $"{genericTypeName} Match<{genericTypeName}>({string.Join(", ", variants.Select(variant => $"global::System.Func<{variant.LocalTypeName}, {genericTypeName}> {FormatIdentifier(variant.ParameterName)}"))})"; private static string FormatSwitchMethodDeclaration(IEnumerable variants) => $"void Switch({string.Join(", ", variants.Select(variant => $"global::System.Action<{variant.LocalTypeName}> {FormatIdentifier(variant.ParameterName)}"))})"; - private static string FormatPartialTypeDeclaration(TypeDeclarationSyntax typeDeclaration) + private static CollectingInterpolatedStringHandler FormatPartialTypeDeclaration(TypeDeclarationSyntax typeDeclaration) => typeDeclaration is RecordDeclarationSyntax recordDeclaration ? CombineTokens("partial", typeDeclaration.Keyword, recordDeclaration.ClassOrStructKeyword, typeDeclaration.Identifier.ToString() + typeDeclaration.TypeParameterList, typeDeclaration.ConstraintClauses) : CombineTokens("partial", typeDeclaration.Keyword, typeDeclaration.Identifier.ToString() + typeDeclaration.TypeParameterList, typeDeclaration.ConstraintClauses); - private static string CombineTokens(params object[] tokens) - => string.Join(" ", tokens.Select(t => t.ToString()).Where(t => !string.IsNullOrEmpty(t))); + private static CollectingInterpolatedStringHandler CombineTokens(params object[] tokens) + => tokens.Select(t => t.ToString()).Where(t => !string.IsNullOrEmpty(t)).JoinToInterpolation(" "); private static string FormatIdentifier(string identifier) => IsIdentifier(identifier) ? '@' + identifier : identifier; private static bool IsIdentifier(string identifier) => SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None; - - // Prevents extra string allocations compared to usages of string.Join before calling the writer. - private static void WriteCommaSeparated(IEnumerable items, Action action, IndentedTextWriter writer) - { - using var enumerator = items.GetEnumerator(); - - if (enumerator.MoveNext()) - { - action(enumerator.Current, writer); - - while (enumerator.MoveNext()) - { - writer.Write(", "); - action(enumerator.Current, writer); - } - } - } } diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj index 45936ff..a20b23b 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj @@ -41,6 +41,6 @@ - + diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/IndentedTextWriterExtensions.cs b/Funcky.DiscriminatedUnion.SourceGeneration/IndentedTextWriterExtensions.cs index b5e13a0..9c62a84 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/IndentedTextWriterExtensions.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/IndentedTextWriterExtensions.cs @@ -22,6 +22,20 @@ public static void OpenScope(this IndentedTextWriter writer) writer.Indent++; } + public static void WriteInterpolated(this IndentedTextWriter writer, CollectingInterpolatedStringHandler value) + { + foreach (var item in value.GetItems()) + { + writer.Write(item?.ToString()); + } + } + + public static void WriteLineInterpolated(this IndentedTextWriter writer, CollectingInterpolatedStringHandler value) + { + writer.WriteInterpolated(value); + writer.WriteLine(); + } + private static void CloseScope(this IndentedTextWriter writer) { writer.Indent--; diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index e4261cd..ed7144c 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -43,8 +43,7 @@ partial record Error [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public static partial class UnionWithPartitionUsageEnumerableExtensions { - public static (global::System.Collections.Generic.IReadOnlyList success, global::System.Collections.Generic.IReadOnlyList warning, global::System.Collections.Generic.IReadOnlyList error) - Partition(this global::System.Collections.Generic.IEnumerable source) + public static (global::System.Collections.Generic.IReadOnlyList success, global::System.Collections.Generic.IReadOnlyList warning, global::System.Collections.Generic.IReadOnlyList error) Partition(this global::System.Collections.Generic.IEnumerable source) { var successItems = new global::System.Collections.Generic.List(); var warningItems = new global::System.Collections.Generic.List(); @@ -53,13 +52,10 @@ public static (global::System.Collections.Generic.IReadOnlyList(this global::System.Collections.Generic.IEnumerable source, global::System.Func, - global::System.Collections.Generic.IReadOnlyList, - global::System.Collections.Generic.IReadOnlyList, - TResult> resultSelector) + public static TResult Partition(this global::System.Collections.Generic.IEnumerable source, global::System.Func, global::System.Collections.Generic.IReadOnlyList, global::System.Collections.Generic.IReadOnlyList, TResult> resultSelector) { var successItems = new global::System.Collections.Generic.List(); var warningItems = new global::System.Collections.Generic.List(); From ae82c6cc7770477222a593e02aa45d4d9573178e Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Wed, 25 Sep 2024 13:22:38 +0200 Subject: [PATCH 13/19] Add test for nested DU with partition --- .../CollectingInterpolatedStringHandler.cs | 5 -- ...tingInterpolatedStringHandlerExtensions.cs | 4 +- ...FlattenedUnionWithPartition.00.verified.cs | 23 ++++++++ ...FlattenedUnionWithPartition.01.verified.cs | 59 +++++++++++++++++++ .../SourceGeneratorTest.cs | 1 + .../Sources/FlattenedUnionWithPartition.cs | 21 +++++++ .../Sources/UnionWithPartitionUsage.cs | 16 +---- 7 files changed, 109 insertions(+), 20 deletions(-) create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.00.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/Sources/FlattenedUnionWithPartition.cs diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs index 494828a..e2fa831 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandler.cs @@ -10,11 +10,6 @@ public CollectingInterpolatedStringHandler(int literalLength, int formattedCount _items = new List(formattedCount * 2); } - public CollectingInterpolatedStringHandler(List items) - { - _items = items; - } - public CollectingInterpolatedStringHandler() { _items = new List(); diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs index 7f0bb07..112b31c 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/CollectingInterpolatedStringHandlerExtensions.cs @@ -10,7 +10,7 @@ public static CollectingInterpolatedStringHandler JoinToInterpolation( if (!enumerator.MoveNext()) { - return default; + return new CollectingInterpolatedStringHandler(); } var result = new CollectingInterpolatedStringHandler(); @@ -35,7 +35,7 @@ public static CollectingInterpolatedStringHandler JoinToInterpolation( if (!enumerator.MoveNext()) { - return default; + return new CollectingInterpolatedStringHandler(); } var result = new CollectingInterpolatedStringHandler(); diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.00.verified.cs new file mode 100644 index 0000000..653d24f --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.00.verified.cs @@ -0,0 +1,23 @@ +//HintName: DiscriminatedUnionAttribute.g.cs +// +#nullable enable + +namespace Funcky +{ + [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")] + [global::System.AttributeUsage(global::System.AttributeTargets.Class)] + internal sealed class DiscriminatedUnionAttribute : global::System.Attribute + { + /// Allow only consumers in the same assembly to use the exhaustive Match and Switch methods. + public bool NonExhaustive { get; set; } + + /// Generates exhaustive Match and Switch methods for the entire type hierarchy. + public bool Flatten { get; set; } + + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . + public bool GeneratePartitionExtension { get; set; } + + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. + public string? MatchResultTypeName { get; set; } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs new file mode 100644 index 0000000..d3389f9 --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs @@ -0,0 +1,59 @@ +//HintName: DiscriminatedUnionGenerator.g.cs +// +#nullable enable + +namespace Funcky.DiscriminatedUnion.Test +{ + partial record FlattenedUnionWithPartition + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public abstract TResult Match(global::System.Func keyword, global::System.Func integer); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public abstract void Switch(global::System.Action keyword, global::System.Action integer); + + partial record Keyword + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override TResult Match(global::System.Func keyword, global::System.Func integer) => keyword(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override void Switch(global::System.Action keyword, global::System.Action integer) => keyword(this); + } + + partial record Integer + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override TResult Match(global::System.Func keyword, global::System.Func integer) => integer(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override void Switch(global::System.Action keyword, global::System.Action integer) => integer(this); + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public static partial class FlattenedUnionWithPartitionEnumerableExtensions + { + public static (global::System.Collections.Generic.IReadOnlyList keyword, global::System.Collections.Generic.IReadOnlyList integer) Partition(this global::System.Collections.Generic.IEnumerable source) + { + var keywordItems = new global::System.Collections.Generic.List(); + var integerItems = new global::System.Collections.Generic.List(); + foreach (var item in source) + { + item.Switch(keyword: keywordItems.Add, integer: integerItems.Add); + } + return (keywordItems.AsReadOnly(), integerItems.AsReadOnly()); + } + + public static TResult Partition(this global::System.Collections.Generic.IEnumerable source, global::System.Func, global::System.Collections.Generic.IReadOnlyList, TResult> resultSelector) + { + var keywordItems = new global::System.Collections.Generic.List(); + var integerItems = new global::System.Collections.Generic.List(); + foreach (var item in source) + { + item.Switch(keyword: keywordItems.Add, integer: integerItems.Add); + } + return resultSelector(keywordItems.AsReadOnly(), integerItems.AsReadOnly()); + } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs index 8598bcd..ca18156 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs @@ -21,6 +21,7 @@ public sealed class SourceGeneratorTest [InlineData("NonExhaustive")] [InlineData("JsonPolymorphic")] [InlineData("UnionWithPartitionUsage")] + [InlineData("FlattenedUnionWithPartition")] public async Task GeneratesExpectedSourceCode(string sourceFileName) => await Verify(sourceFileName); [Fact] diff --git a/Funcky.DiscriminatedUnion.Test/Sources/FlattenedUnionWithPartition.cs b/Funcky.DiscriminatedUnion.Test/Sources/FlattenedUnionWithPartition.cs new file mode 100644 index 0000000..74210c5 --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/Sources/FlattenedUnionWithPartition.cs @@ -0,0 +1,21 @@ +namespace Funcky.DiscriminatedUnion.Test; + +[DiscriminatedUnion(Flatten = true, GeneratePartitionExtension = true)] +public abstract partial record FlattenedUnionWithPartition +{ + public sealed partial record Keyword(string Value) : FlattenedUnionWithPartition; + + public abstract partial record Literal : FlattenedUnionWithPartition; + + public abstract partial record Number : Literal; + + public sealed partial record Integer(int Value) : Number; +} + +public static class FlattenedUnionWithPartitionTest +{ + public static void Test(FlattenedUnionWithPartition[] items) + { + var (keywords, integers) = items.Partition(); + } +} diff --git a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs index 9ec66d8..2cd0279 100644 --- a/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs +++ b/Funcky.DiscriminatedUnion.Test/Sources/UnionWithPartitionUsage.cs @@ -12,20 +12,10 @@ public sealed partial record Error : UnionWithPartitionUsage; public static class UnionWithPartitionUsageTest { - public static void Test() + public static void Test(UnionWithPartitionUsage[] items) { - var instances = new UnionWithPartitionUsage[] - { - new UnionWithPartitionUsage.Success(), - new UnionWithPartitionUsage.Warning(), - new UnionWithPartitionUsage.Error(), - new UnionWithPartitionUsage.Success(), - new UnionWithPartitionUsage.Warning(), - new UnionWithPartitionUsage.Warning(), - }; + var (successes, warnings, errors) = items.Partition(); - var (successes, warnings, errors) = instances.Partition(); - - var warningsAndErrorsCount = instances.Partition(resultSelector: (_, w, e) => w.Count + e.Count); + int _ = items.Partition(resultSelector: (_, w, e) => w.Count + e.Count); } } From 1334c9dc5f436a9aef7512edd2edbc9ecf8bfaae Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Wed, 25 Sep 2024 13:26:57 +0200 Subject: [PATCH 14/19] Add test for nested flattened union type for partition generation --- ...nedNestedUnionWithPartition.00.verified.cs | 23 +++++++ ...nedNestedUnionWithPartition.01.verified.cs | 65 +++++++++++++++++++ .../SourceGeneratorTest.cs | 1 + .../FlattenedNestedUnionWithPartition.cs | 23 +++++++ 4 files changed, 112 insertions(+) create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.00.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs create mode 100644 Funcky.DiscriminatedUnion.Test/Sources/FlattenedNestedUnionWithPartition.cs diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.00.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.00.verified.cs new file mode 100644 index 0000000..653d24f --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.00.verified.cs @@ -0,0 +1,23 @@ +//HintName: DiscriminatedUnionAttribute.g.cs +// +#nullable enable + +namespace Funcky +{ + [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")] + [global::System.AttributeUsage(global::System.AttributeTargets.Class)] + internal sealed class DiscriminatedUnionAttribute : global::System.Attribute + { + /// Allow only consumers in the same assembly to use the exhaustive Match and Switch methods. + public bool NonExhaustive { get; set; } + + /// Generates exhaustive Match and Switch methods for the entire type hierarchy. + public bool Flatten { get; set; } + + /// If a specialized partition extension method for IEnumerable should be generated. Defaults to . + public bool GeneratePartitionExtension { get; set; } + + /// Customized the generic type name used for the result in the generated Match methods. Defaults to TResult. + public string? MatchResultTypeName { get; set; } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs new file mode 100644 index 0000000..958c82b --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs @@ -0,0 +1,65 @@ +//HintName: DiscriminatedUnionGenerator.g.cs +// +#nullable enable + +namespace Funcky.DiscriminatedUnion.Test +{ + partial record FlattenedNestedUnionWithPartition + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public abstract TResult Match(global::System.Func keyword, global::System.Func integer); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public abstract void Switch(global::System.Action keyword, global::System.Action integer); + + partial record Keyword + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override TResult Match(global::System.Func keyword, global::System.Func integer) => keyword(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override void Switch(global::System.Action keyword, global::System.Action integer) => keyword(this); + } + + partial record Literal + { + partial record Number + { + partial record Integer + { + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override TResult Match(global::System.Func keyword, global::System.Func integer) => integer(this); + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public override void Switch(global::System.Action keyword, global::System.Action integer) => integer(this); + } + } + } + } + + [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] + public static partial class FlattenedNestedUnionWithPartitionEnumerableExtensions + { + public static (global::System.Collections.Generic.IReadOnlyList keyword, global::System.Collections.Generic.IReadOnlyList integer) Partition(this global::System.Collections.Generic.IEnumerable source) + { + var keywordItems = new global::System.Collections.Generic.List(); + var integerItems = new global::System.Collections.Generic.List(); + foreach (var item in source) + { + item.Switch(keyword: keywordItems.Add, integer: integerItems.Add); + } + return (keywordItems.AsReadOnly(), integerItems.AsReadOnly()); + } + + public static TResult Partition(this global::System.Collections.Generic.IEnumerable source, global::System.Func, global::System.Collections.Generic.IReadOnlyList, TResult> resultSelector) + { + var keywordItems = new global::System.Collections.Generic.List(); + var integerItems = new global::System.Collections.Generic.List(); + foreach (var item in source) + { + item.Switch(keyword: keywordItems.Add, integer: integerItems.Add); + } + return resultSelector(keywordItems.AsReadOnly(), integerItems.AsReadOnly()); + } + } +} diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs index ca18156..c90b294 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.cs @@ -22,6 +22,7 @@ public sealed class SourceGeneratorTest [InlineData("JsonPolymorphic")] [InlineData("UnionWithPartitionUsage")] [InlineData("FlattenedUnionWithPartition")] + [InlineData("FlattenedNestedUnionWithPartition")] public async Task GeneratesExpectedSourceCode(string sourceFileName) => await Verify(sourceFileName); [Fact] diff --git a/Funcky.DiscriminatedUnion.Test/Sources/FlattenedNestedUnionWithPartition.cs b/Funcky.DiscriminatedUnion.Test/Sources/FlattenedNestedUnionWithPartition.cs new file mode 100644 index 0000000..08da131 --- /dev/null +++ b/Funcky.DiscriminatedUnion.Test/Sources/FlattenedNestedUnionWithPartition.cs @@ -0,0 +1,23 @@ +namespace Funcky.DiscriminatedUnion.Test; + +[DiscriminatedUnion(Flatten = true, GeneratePartitionExtension = true)] +public abstract partial record FlattenedNestedUnionWithPartition +{ + public sealed partial record Keyword(string Value) : FlattenedNestedUnionWithPartition; + + public abstract partial record Literal : FlattenedNestedUnionWithPartition + { + public abstract partial record Number : Literal + { + public sealed partial record Integer(int Value) : Number; + } + } +} + +public static class FlattenedNestedUnionWithPartitionTest +{ + public static void Test(FlattenedNestedUnionWithPartition[] items) + { + var (keywords, integers) = items.Partition(); + } +} From 3e97880725a2f12177656b7e68e63ce82430be11 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Wed, 25 Sep 2024 13:31:50 +0200 Subject: [PATCH 15/19] Use interpolation over string concat and join --- Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index 09db2fe..ea34c51 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.CodeDom.Compiler; -using System.Runtime.CompilerServices; using System.Text; using static Funcky.DiscriminatedUnion.SourceGeneration.SourceCodeSnippets; @@ -173,10 +172,10 @@ private static void WriteJsonDerivedTypeAttribute(IndentedTextWriter writer, Dis } private static CollectingInterpolatedStringHandler FormatMatchMethodDeclaration(string genericTypeName, IEnumerable variants) - => $"{genericTypeName} Match<{genericTypeName}>({string.Join(", ", variants.Select(variant => $"global::System.Func<{variant.LocalTypeName}, {genericTypeName}> {FormatIdentifier(variant.ParameterName)}"))})"; + => $"{genericTypeName} Match<{genericTypeName}>({variants.JoinToInterpolation(v => $"global::System.Func<{v.LocalTypeName}, {genericTypeName}> {FormatIdentifier(v.ParameterName)}", ", ")})"; - private static string FormatSwitchMethodDeclaration(IEnumerable variants) - => $"void Switch({string.Join(", ", variants.Select(variant => $"global::System.Action<{variant.LocalTypeName}> {FormatIdentifier(variant.ParameterName)}"))})"; + private static CollectingInterpolatedStringHandler FormatSwitchMethodDeclaration(IEnumerable variants) + => $"void Switch({variants.JoinToInterpolation(v => $"global::System.Action<{v.LocalTypeName}> {FormatIdentifier(v.ParameterName)}", ", ")})"; private static CollectingInterpolatedStringHandler FormatPartialTypeDeclaration(TypeDeclarationSyntax typeDeclaration) => typeDeclaration is RecordDeclarationSyntax recordDeclaration @@ -186,8 +185,8 @@ private static CollectingInterpolatedStringHandler FormatPartialTypeDeclaration( private static CollectingInterpolatedStringHandler CombineTokens(params object[] tokens) => tokens.Select(t => t.ToString()).Where(t => !string.IsNullOrEmpty(t)).JoinToInterpolation(" "); - private static string FormatIdentifier(string identifier) - => IsIdentifier(identifier) ? '@' + identifier : identifier; + private static CollectingInterpolatedStringHandler FormatIdentifier(string identifier) + => $"{(IsIdentifier(identifier) ? "@" : string.Empty)}{identifier}"; private static bool IsIdentifier(string identifier) => SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None; From ce68064c4837a0e62d0cdfb7d7486dccc8510875 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 1 Oct 2024 10:30:42 +0200 Subject: [PATCH 16/19] Replace Menzantiou.Polyfill with PolySharp --- .../Funcky.DiscriminatedUnion.SourceGeneration.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj index a20b23b..67b24d1 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Funcky.DiscriminatedUnion.SourceGeneration.csproj @@ -41,6 +41,6 @@ - + From 0f7730c701f9e4013526b256bb92fed9418aca28 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 1 Oct 2024 10:32:42 +0200 Subject: [PATCH 17/19] Improve naming --- .../DiscriminatedUnion.cs | 2 +- Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs | 10 +++++----- Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs index 5b85ff5..13eb39e 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/DiscriminatedUnion.cs @@ -6,7 +6,7 @@ internal sealed record DiscriminatedUnion( TypeDeclarationSyntax Type, IReadOnlyList ParentTypes, string? Namespace, - string MethodVisibility, + string GeneratedMethodOrClassVisibility, string MatchResultTypeName, IReadOnlyList Variants, bool GeneratePartitionExtension); diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index ea34c51..4392e88 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -39,9 +39,9 @@ private static void WriteUnionType(DiscriminatedUnion discriminatedUnion, Indent writer.WriteLineInterpolated(FormatPartialTypeDeclaration(discriminatedUnion.Type)); writer.OpenScope(); - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)};"); + WriteGeneratedMethod(writer, $"{discriminatedUnion.GeneratedMethodOrClassVisibility} abstract {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)};"); writer.WriteLine(); - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} abstract {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)};"); + WriteGeneratedMethod(writer, $"{discriminatedUnion.GeneratedMethodOrClassVisibility} abstract {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)};"); foreach (var variant in discriminatedUnion.Variants) { @@ -54,7 +54,7 @@ private static void WritePartitionExtensions(DiscriminatedUnion discriminatedUni using var scope = writer.AutoCloseScopes(); writer.WriteLine(GeneratedCodeAttributeSource); - writer.WriteLineInterpolated($"{discriminatedUnion.MethodVisibility} static partial class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); + writer.WriteLineInterpolated($"{discriminatedUnion.GeneratedMethodOrClassVisibility} static partial class {discriminatedUnion.Type.Identifier}EnumerableExtensions"); writer.OpenScope(); WriteTupleReturningPartitionExtension(discriminatedUnion, writer); @@ -143,9 +143,9 @@ private static void WriteVariant(IndentedTextWriter writer, DiscriminatedUnion d writer.WriteLineInterpolated(FormatPartialTypeDeclaration(variant.Type)); writer.OpenScope(); - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} override {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)} => {FormatIdentifier(variant.ParameterName)}(this);"); + WriteGeneratedMethod(writer, $"{discriminatedUnion.GeneratedMethodOrClassVisibility} override {FormatMatchMethodDeclaration(discriminatedUnion.MatchResultTypeName, discriminatedUnion.Variants)} => {FormatIdentifier(variant.ParameterName)}(this);"); writer.WriteLine(); - WriteGeneratedMethod(writer, $"{discriminatedUnion.MethodVisibility} override {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)} => {FormatIdentifier(variant.ParameterName)}(this);"); + WriteGeneratedMethod(writer, $"{discriminatedUnion.GeneratedMethodOrClassVisibility} override {FormatSwitchMethodDeclaration(discriminatedUnion.Variants)} => {FormatIdentifier(variant.ParameterName)}(this);"); } } diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs index a086318..1f0dea5 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Parser.cs @@ -38,7 +38,7 @@ public static bool IsSyntaxTargetForGeneration(SyntaxNode node) ParentTypes: typeDeclaration.Ancestors().OfType().ToList(), Namespace: FormatNamespace(typeSymbol), MatchResultTypeName: matchResultType ?? "TResult", - MethodVisibility: nonExhaustive ? "internal" : "public", + GeneratedMethodOrClassVisibility: nonExhaustive ? "internal" : "public", GeneratePartitionExtension: generatePartitionExtension, Variants: GetVariantTypeDeclarations(typeDeclaration, isVariant) .Select(GetDiscriminatedUnionVariant(typeDeclaration, semanticModel, GenerateJsonDerivedTypeAttribute(typeSymbol))) From 0f0fd7efdad06249d96b8915ff8bab7f68aa207d Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 1 Oct 2024 10:42:53 +0200 Subject: [PATCH 18/19] Upper-Case first character of tuple names in return value of partition method --- Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs | 2 +- ...rceFileName=FlattenedNestedUnionWithPartition.01.verified.cs | 2 +- ...de_sourceFileName=FlattenedUnionWithPartition.01.verified.cs | 2 +- ...ceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs index 4392e88..b457a8a 100644 --- a/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs +++ b/Funcky.DiscriminatedUnion.SourceGeneration/Emitter.cs @@ -69,7 +69,7 @@ private static void WriteTupleReturningPartitionExtension(DiscriminatedUnion dis var namedResultPartitions = discriminatedUnion .Variants .JoinToInterpolation( - v => $"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName}", + v => $"global::System.Collections.Generic.IReadOnlyList<{discriminatedUnion.Type.Identifier}.{v.LocalTypeName}> {v.ParameterName[..1].ToUpper()}{v.ParameterName[1..]}", ", "); writer.WriteLineInterpolated($"public static ({namedResultPartitions}) Partition(this global::System.Collections.Generic.IEnumerable<{discriminatedUnion.Type.Identifier}> source)"); diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs index 958c82b..9c3bf92 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedNestedUnionWithPartition.01.verified.cs @@ -40,7 +40,7 @@ partial record Integer [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public static partial class FlattenedNestedUnionWithPartitionEnumerableExtensions { - public static (global::System.Collections.Generic.IReadOnlyList keyword, global::System.Collections.Generic.IReadOnlyList integer) Partition(this global::System.Collections.Generic.IEnumerable source) + public static (global::System.Collections.Generic.IReadOnlyList Keyword, global::System.Collections.Generic.IReadOnlyList Integer) Partition(this global::System.Collections.Generic.IEnumerable source) { var keywordItems = new global::System.Collections.Generic.List(); var integerItems = new global::System.Collections.Generic.List(); diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs index d3389f9..6bc51e7 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=FlattenedUnionWithPartition.01.verified.cs @@ -34,7 +34,7 @@ partial record Integer [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public static partial class FlattenedUnionWithPartitionEnumerableExtensions { - public static (global::System.Collections.Generic.IReadOnlyList keyword, global::System.Collections.Generic.IReadOnlyList integer) Partition(this global::System.Collections.Generic.IEnumerable source) + public static (global::System.Collections.Generic.IReadOnlyList Keyword, global::System.Collections.Generic.IReadOnlyList Integer) Partition(this global::System.Collections.Generic.IEnumerable source) { var keywordItems = new global::System.Collections.Generic.List(); var integerItems = new global::System.Collections.Generic.List(); diff --git a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs index ed7144c..be2fb07 100644 --- a/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs +++ b/Funcky.DiscriminatedUnion.Test/SourceGeneratorTest.GeneratesExpectedSourceCode_sourceFileName=UnionWithPartitionUsage.01.verified.cs @@ -43,7 +43,7 @@ partial record Error [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.2.0.0")] public static partial class UnionWithPartitionUsageEnumerableExtensions { - public static (global::System.Collections.Generic.IReadOnlyList success, global::System.Collections.Generic.IReadOnlyList warning, global::System.Collections.Generic.IReadOnlyList error) Partition(this global::System.Collections.Generic.IEnumerable source) + public static (global::System.Collections.Generic.IReadOnlyList Success, global::System.Collections.Generic.IReadOnlyList Warning, global::System.Collections.Generic.IReadOnlyList Error) Partition(this global::System.Collections.Generic.IEnumerable source) { var successItems = new global::System.Collections.Generic.List(); var warningItems = new global::System.Collections.Generic.List(); From 93c1c0759c49717ccbeb9508ba0eda9f78773069 Mon Sep 17 00:00:00 2001 From: Mathias Fischler Date: Tue, 1 Oct 2024 11:10:09 +0200 Subject: [PATCH 19/19] Update readme with example for partition --- readme.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/readme.md b/readme.md index 4c73082..7fa8ef2 100644 --- a/readme.md +++ b/readme.md @@ -130,4 +130,38 @@ partial record Shape +### `GeneratePartitionExtension` +Set `GeneratePartitionExtension` to true to auto-generate partition methods for `IEnumerable` of your type. + +```cs +using Funcky; +using System.Text.Serialization; + +[DiscriminatedUnion(GeneratePartitionExtension = true)] +public abstract partial record Result +{ + public sealed partial record Ok() : Result; + + public sealed partial record Warning(string Message) : Result; + + public sealed partial record Error(string Message) : Result; +} +``` + +
+ +Usage + +```cs +var results = new Result[] { new Result.Ok(), /* ... */ } + +// N-Tuple extension method: +var (oks, warnings, errors) = results.Partition(); + +// Extension method with result selector: +var warningAndErrorCount = results.Partition(resultSelector: (_, warnings, errors) => warnings.Count + errors.Count); +``` + +
+ [json-polymorphism-docs]: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism