diff --git a/Source/Sundew.DiscriminatedUnions.Api.Generator/Sundew.DiscriminatedUnions.Api.Generator.csproj b/Source/Sundew.DiscriminatedUnions.Api.Generator/Sundew.DiscriminatedUnions.Api.Generator.csproj index b05c3c5..1ddd3ef 100644 --- a/Source/Sundew.DiscriminatedUnions.Api.Generator/Sundew.DiscriminatedUnions.Api.Generator.csproj +++ b/Source/Sundew.DiscriminatedUnions.Api.Generator/Sundew.DiscriminatedUnions.Api.Generator.csproj @@ -1,9 +1,9 @@  - net7.0 + net8.0 false - win10-x64;osx.10.12-x64;debian.8-x64 + win-x64;osx-x64;linux-x64 enable Exe AnyCPU diff --git a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/CodeAnalysisHelper.cs b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/CodeAnalysisHelper.cs index 05194e4..19bb369 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/CodeAnalysisHelper.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/CodeAnalysisHelper.cs @@ -16,9 +16,13 @@ namespace Sundew.DiscriminatedUnions.Generator; using Sundew.DiscriminatedUnions.Generator.Model; using Sundew.DiscriminatedUnions.Shared; using static Sundew.DiscriminatedUnions.Generator.OutputStage.GeneratorConstants; +using Type = Sundew.DiscriminatedUnions.Generator.Model.Type; internal static class CodeAnalysisHelper { + private const string? OutText = "out"; + private const string? InText = "in"; + private static readonly HashSet Keywords = new HashSet { "abstract", @@ -172,18 +176,6 @@ public static Type GetSourceType(this ITypeSymbol typeSymbol) public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQualifiedFormat = false) { - string? GetGenericQualifier(INamedTypeSymbol namedTypeSymbol) - { - var name = namedTypeSymbol.ToDisplayString(useFullyQualifiedFormat ? FullyQualifiedDisplayFormat : NameQualifiedTypeFormat); - var index = name.IndexOf('<'); - if (index > -1) - { - return name.Substring(index); - } - - return null; - } - switch (typeSymbol) { case INamedTypeSymbol namedTypeSymbol: @@ -195,12 +187,10 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua isShortNameAlias ? string.Empty : GlobalAssemblyAlias, false, new TypeMetadata( - !isShortNameAlias && namedTypeSymbol.IsTypeGenericWithTypeParameters() - ? GetGenericQualifier(namedTypeSymbol) - : null, fullName, namedTypeSymbol.TypeParameters.Select(x => new TypeParameter( x.Name, + x.Variance, GetUnderlyingTypeConstraint(x) .Concat(x.ConstraintTypes.Select(x => x.ToDisplayString(FullyQualifiedDisplayFormat))) @@ -213,9 +203,9 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua elementAttributeName, elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias, true, - new TypeMetadata(null, elementFullName, ImmutableArray.Empty)); + new TypeMetadata(elementFullName, ImmutableArray.Empty)); case ITypeParameterSymbol typeParameterSymbol: - return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, string.Empty, ImmutableArray.Empty)); + return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(string.Empty, ImmutableArray.Empty)); default: throw new System.ArgumentOutOfRangeException(nameof(typeSymbol)); } diff --git a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/DeclarationStage/TypeParameter.cs b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/DeclarationStage/TypeParameter.cs index 5e4f036..ab966cd 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/DeclarationStage/TypeParameter.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/DeclarationStage/TypeParameter.cs @@ -7,6 +7,7 @@ namespace Sundew.DiscriminatedUnions.Generator.DeclarationStage; +using Microsoft.CodeAnalysis; using Sundew.Base.Collections.Immutable; -internal readonly record struct TypeParameter(string Name, ValueArray Constraints); \ No newline at end of file +internal readonly record struct TypeParameter(string Name, VarianceKind VarianceKind, ValueArray Constraints); \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/Model/TypeMetadata.cs b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/Model/TypeMetadata.cs index 6d8394a..c1bc78f 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/Model/TypeMetadata.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/Model/TypeMetadata.cs @@ -10,4 +10,4 @@ namespace Sundew.DiscriminatedUnions.Generator.Model; using Sundew.Base.Collections.Immutable; using Sundew.DiscriminatedUnions.Generator.DeclarationStage; -internal readonly record struct TypeMetadata(string? GenericQualifier, string FullName, ValueArray TypeParameters); \ No newline at end of file +internal readonly record struct TypeMetadata(string FullName, ValueArray TypeParameters); \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/DiscriminatedUnionOutputProvider.cs b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/DiscriminatedUnionOutputProvider.cs index 634a29c..828c73f 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/DiscriminatedUnionOutputProvider.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/DiscriminatedUnionOutputProvider.cs @@ -112,7 +112,7 @@ private static string GetUnionSource(in DiscriminatedUnion discriminatedUnion, s .Append(' ') .AppendUnderlyingType(discriminatedUnion.UnderlyingType) .Append(' ') - .AppendType(discriminatedUnion.Type, false) + .AppendType(discriminatedUnion.Type, false, false, true) .AppendLine() .TryAppendConstraints(discriminatedUnion.Type.TypeMetadata.TypeParameters, SpaceIndentedBy8) .AppendPragmaWarning(true, Sa1601) diff --git a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/StringBuilderExtensions.cs b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/StringBuilderExtensions.cs index 6469756..880de03 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/StringBuilderExtensions.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator.Baseline/OutputStage/StringBuilderExtensions.cs @@ -12,6 +12,7 @@ namespace Sundew.DiscriminatedUnions.Generator.OutputStage; using System.Linq; using System.Reflection; using System.Text; +using Microsoft.CodeAnalysis; using Sundew.Base.Collections.Immutable; using Sundew.Base.Text; using Sundew.DiscriminatedUnions.Generator.DeclarationStage; @@ -39,8 +40,10 @@ internal static class StringBuilderExtensions private const string SummaryStart = "/// "; private const string SummaryEnd = "/// "; private const string Documentation = "/// "; + private const string OutText = "out"; + private const string InText = "in"; - public static StringBuilder AppendType(this StringBuilder stringBuilder, in FullType fullType, bool fullyQualify = true, bool omitTypeParameters = false) + public static StringBuilder AppendType(this StringBuilder stringBuilder, in FullType fullType, bool fullyQualify = true, bool isForAttribute = false, bool isForPartial = false) { if (fullyQualify && fullType.Namespace != string.Empty) { @@ -51,7 +54,18 @@ public static StringBuilder AppendType(this StringBuilder stringBuilder, in Full .Append('.'); } - stringBuilder.Append(omitTypeParameters ? fullType.NameForTypeOfAttribute : fullType.TypeMetadata.FullName); + if (isForAttribute) + { + stringBuilder.Append(fullType.NameForTypeOfAttribute); + } + else if (isForPartial) + { + stringBuilder.Append(fullType.Name).TryAppendGenericQualifier(fullType, false, false); + } + else + { + stringBuilder.Append(fullType.TypeMetadata.FullName); + } if (fullType.IsArray) { @@ -61,22 +75,40 @@ public static StringBuilder AppendType(this StringBuilder stringBuilder, in Full return stringBuilder; } - public static StringBuilder TryAppendGenericQualifier(this StringBuilder stringBuilder, in FullType fullType, bool omitTypeParameters = false) + public static StringBuilder TryAppendGenericQualifier(this StringBuilder stringBuilder, in FullType fullType, bool omitTypeParameters = false, bool omitVariance = true) { - if (fullType.TypeMetadata.GenericQualifier != null) + string GetVariance(TypeParameter typeParameter) { - if (!omitTypeParameters) + return typeParameter.VarianceKind switch { - stringBuilder.Append(fullType.TypeMetadata.GenericQualifier); - } - else + VarianceKind.None => throw new ArgumentOutOfRangeException(), + VarianceKind.Out => OutText, + VarianceKind.In => InText, + _ => throw new UnreachableCaseException(typeParameter.VarianceKind.GetType()), + }; + } + + var typeParameterCount = fullType.TypeMetadata.TypeParameters.Count; + if (typeParameterCount > 0) + { + if (!omitTypeParameters) { - var typeParameterCount = fullType.TypeMetadata.TypeParameters.Count; + const string separator = ", "; stringBuilder .Append('<') - .If(typeParameterCount > 0, stringBuilder => stringBuilder.Append(',', typeParameterCount - 1)) + .AppendItems( + fullType.TypeMetadata.TypeParameters, + (builder, typeParameter) => + { + builder.If(!omitVariance && typeParameter.VarianceKind != VarianceKind.None, builder => builder.Append(GetVariance(typeParameter)).Append(' ')).Append(typeParameter.Name); + }, + separator) .Append('>'); } + else + { + stringBuilder.Append('<').Append(',', typeParameterCount - 1).Append('>'); + } } return stringBuilder; diff --git a/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterExtensions{T}.generated.verified.cs b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterExtensions{T}.generated.verified.cs new file mode 100644 index 0000000..5667bf7 --- /dev/null +++ b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterExtensions{T}.generated.verified.cs @@ -0,0 +1,36 @@ +//HintName: Sundew.DiscriminatedUnions.Tester.IGenericOutParameterExtensions{T}.generated.cs +#nullable enable + +namespace Sundew.DiscriminatedUnions.Tester +{ + /// + /// Segregation extension method for IGenericOutParameter. + /// + [global::System.Diagnostics.DebuggerNonUserCode] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.3.0.0")] + public static partial class IGenericOutParameterExtensions + { + /// + /// Segregates the items in the specified enumerable by type. + /// + /// The iGenericOutParameters. + /// A new IGenericOutParameterSegregation. + public static IGenericOutParameterSegregation Segregate(this System.Collections.Generic.IEnumerable> iGenericOutParameters) + where T : notnull + { + var genericOutParameters = new System.Collections.Generic.List>(); + + foreach (var value in iGenericOutParameters) + { + switch (value) + { + case global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter genericOutParameter: + genericOutParameters.Add(genericOutParameter); + break; + } + } + + return new global::Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation(genericOutParameters); + } + } +} \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation{T}.generated.verified.cs b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation{T}.generated.verified.cs new file mode 100644 index 0000000..8eba4a4 --- /dev/null +++ b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation{T}.generated.verified.cs @@ -0,0 +1,25 @@ +//HintName: Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation{T}.generated.cs +#nullable enable + +namespace Sundew.DiscriminatedUnions.Tester +{ + /// + /// Contains individual lists of the different cases of the discriminated union IGenericOutParameter. + /// + [global::System.Diagnostics.DebuggerNonUserCode] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.3.0.0")] + public sealed partial class IGenericOutParameterSegregation + where T : notnull + { + internal IGenericOutParameterSegregation(System.Collections.Generic.IReadOnlyList> genericOutParameters) + { + this.GenericOutParameters = genericOutParameters; + } + + /// + /// Gets the GenericOutParameters. + /// + /// The GenericOutParameters. + public System.Collections.Generic.IReadOnlyList> GenericOutParameters { get; } + } +} \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameter{T}.generated.verified.cs b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameter{T}.generated.verified.cs new file mode 100644 index 0000000..6cde068 --- /dev/null +++ b/Source/Sundew.DiscriminatedUnions.Generator.IntegrationTests/DiscriminatedUnionGeneratorFixture.VerifyGeneratedSources#Sundew.DiscriminatedUnions.Tester.IGenericOutParameter{T}.generated.verified.cs @@ -0,0 +1,22 @@ +//HintName: Sundew.DiscriminatedUnions.Tester.IGenericOutParameter{T}.generated.cs +#nullable enable + +namespace Sundew.DiscriminatedUnions.Tester +{ +#pragma warning disable SA1601 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.3.0.0")] + public partial interface IGenericOutParameter + where T : notnull +#pragma warning restore SA1601 + { + /// + /// Factory method for the GenericOutParameter case. + /// + /// The value. + /// A new GenericOutParameter. + [Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<>))] + [global::System.Diagnostics.DebuggerNonUserCode] + public static global::Sundew.DiscriminatedUnions.Tester.IGenericOutParameter GenericOutParameter(T value) + => new global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter(value); + } +} diff --git a/Source/Sundew.DiscriminatedUnions.Generator/CodeAnalysisHelper.cs b/Source/Sundew.DiscriminatedUnions.Generator/CodeAnalysisHelper.cs index 05194e4..19bb369 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator/CodeAnalysisHelper.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator/CodeAnalysisHelper.cs @@ -16,9 +16,13 @@ namespace Sundew.DiscriminatedUnions.Generator; using Sundew.DiscriminatedUnions.Generator.Model; using Sundew.DiscriminatedUnions.Shared; using static Sundew.DiscriminatedUnions.Generator.OutputStage.GeneratorConstants; +using Type = Sundew.DiscriminatedUnions.Generator.Model.Type; internal static class CodeAnalysisHelper { + private const string? OutText = "out"; + private const string? InText = "in"; + private static readonly HashSet Keywords = new HashSet { "abstract", @@ -172,18 +176,6 @@ public static Type GetSourceType(this ITypeSymbol typeSymbol) public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQualifiedFormat = false) { - string? GetGenericQualifier(INamedTypeSymbol namedTypeSymbol) - { - var name = namedTypeSymbol.ToDisplayString(useFullyQualifiedFormat ? FullyQualifiedDisplayFormat : NameQualifiedTypeFormat); - var index = name.IndexOf('<'); - if (index > -1) - { - return name.Substring(index); - } - - return null; - } - switch (typeSymbol) { case INamedTypeSymbol namedTypeSymbol: @@ -195,12 +187,10 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua isShortNameAlias ? string.Empty : GlobalAssemblyAlias, false, new TypeMetadata( - !isShortNameAlias && namedTypeSymbol.IsTypeGenericWithTypeParameters() - ? GetGenericQualifier(namedTypeSymbol) - : null, fullName, namedTypeSymbol.TypeParameters.Select(x => new TypeParameter( x.Name, + x.Variance, GetUnderlyingTypeConstraint(x) .Concat(x.ConstraintTypes.Select(x => x.ToDisplayString(FullyQualifiedDisplayFormat))) @@ -213,9 +203,9 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua elementAttributeName, elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias, true, - new TypeMetadata(null, elementFullName, ImmutableArray.Empty)); + new TypeMetadata(elementFullName, ImmutableArray.Empty)); case ITypeParameterSymbol typeParameterSymbol: - return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, string.Empty, ImmutableArray.Empty)); + return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(string.Empty, ImmutableArray.Empty)); default: throw new System.ArgumentOutOfRangeException(nameof(typeSymbol)); } diff --git a/Source/Sundew.DiscriminatedUnions.Generator/DeclarationStage/TypeParameter.cs b/Source/Sundew.DiscriminatedUnions.Generator/DeclarationStage/TypeParameter.cs index 5e4f036..ab966cd 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator/DeclarationStage/TypeParameter.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator/DeclarationStage/TypeParameter.cs @@ -7,6 +7,7 @@ namespace Sundew.DiscriminatedUnions.Generator.DeclarationStage; +using Microsoft.CodeAnalysis; using Sundew.Base.Collections.Immutable; -internal readonly record struct TypeParameter(string Name, ValueArray Constraints); \ No newline at end of file +internal readonly record struct TypeParameter(string Name, VarianceKind VarianceKind, ValueArray Constraints); \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator/Model/TypeMetadata.cs b/Source/Sundew.DiscriminatedUnions.Generator/Model/TypeMetadata.cs index 6d8394a..c1bc78f 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator/Model/TypeMetadata.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator/Model/TypeMetadata.cs @@ -10,4 +10,4 @@ namespace Sundew.DiscriminatedUnions.Generator.Model; using Sundew.Base.Collections.Immutable; using Sundew.DiscriminatedUnions.Generator.DeclarationStage; -internal readonly record struct TypeMetadata(string? GenericQualifier, string FullName, ValueArray TypeParameters); \ No newline at end of file +internal readonly record struct TypeMetadata(string FullName, ValueArray TypeParameters); \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/DiscriminatedUnionOutputProvider.cs b/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/DiscriminatedUnionOutputProvider.cs index 634a29c..828c73f 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/DiscriminatedUnionOutputProvider.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/DiscriminatedUnionOutputProvider.cs @@ -112,7 +112,7 @@ private static string GetUnionSource(in DiscriminatedUnion discriminatedUnion, s .Append(' ') .AppendUnderlyingType(discriminatedUnion.UnderlyingType) .Append(' ') - .AppendType(discriminatedUnion.Type, false) + .AppendType(discriminatedUnion.Type, false, false, true) .AppendLine() .TryAppendConstraints(discriminatedUnion.Type.TypeMetadata.TypeParameters, SpaceIndentedBy8) .AppendPragmaWarning(true, Sa1601) diff --git a/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/StringBuilderExtensions.cs b/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/StringBuilderExtensions.cs index 6469756..880de03 100644 --- a/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/StringBuilderExtensions.cs +++ b/Source/Sundew.DiscriminatedUnions.Generator/OutputStage/StringBuilderExtensions.cs @@ -12,6 +12,7 @@ namespace Sundew.DiscriminatedUnions.Generator.OutputStage; using System.Linq; using System.Reflection; using System.Text; +using Microsoft.CodeAnalysis; using Sundew.Base.Collections.Immutable; using Sundew.Base.Text; using Sundew.DiscriminatedUnions.Generator.DeclarationStage; @@ -39,8 +40,10 @@ internal static class StringBuilderExtensions private const string SummaryStart = "/// "; private const string SummaryEnd = "/// "; private const string Documentation = "/// "; + private const string OutText = "out"; + private const string InText = "in"; - public static StringBuilder AppendType(this StringBuilder stringBuilder, in FullType fullType, bool fullyQualify = true, bool omitTypeParameters = false) + public static StringBuilder AppendType(this StringBuilder stringBuilder, in FullType fullType, bool fullyQualify = true, bool isForAttribute = false, bool isForPartial = false) { if (fullyQualify && fullType.Namespace != string.Empty) { @@ -51,7 +54,18 @@ public static StringBuilder AppendType(this StringBuilder stringBuilder, in Full .Append('.'); } - stringBuilder.Append(omitTypeParameters ? fullType.NameForTypeOfAttribute : fullType.TypeMetadata.FullName); + if (isForAttribute) + { + stringBuilder.Append(fullType.NameForTypeOfAttribute); + } + else if (isForPartial) + { + stringBuilder.Append(fullType.Name).TryAppendGenericQualifier(fullType, false, false); + } + else + { + stringBuilder.Append(fullType.TypeMetadata.FullName); + } if (fullType.IsArray) { @@ -61,22 +75,40 @@ public static StringBuilder AppendType(this StringBuilder stringBuilder, in Full return stringBuilder; } - public static StringBuilder TryAppendGenericQualifier(this StringBuilder stringBuilder, in FullType fullType, bool omitTypeParameters = false) + public static StringBuilder TryAppendGenericQualifier(this StringBuilder stringBuilder, in FullType fullType, bool omitTypeParameters = false, bool omitVariance = true) { - if (fullType.TypeMetadata.GenericQualifier != null) + string GetVariance(TypeParameter typeParameter) { - if (!omitTypeParameters) + return typeParameter.VarianceKind switch { - stringBuilder.Append(fullType.TypeMetadata.GenericQualifier); - } - else + VarianceKind.None => throw new ArgumentOutOfRangeException(), + VarianceKind.Out => OutText, + VarianceKind.In => InText, + _ => throw new UnreachableCaseException(typeParameter.VarianceKind.GetType()), + }; + } + + var typeParameterCount = fullType.TypeMetadata.TypeParameters.Count; + if (typeParameterCount > 0) + { + if (!omitTypeParameters) { - var typeParameterCount = fullType.TypeMetadata.TypeParameters.Count; + const string separator = ", "; stringBuilder .Append('<') - .If(typeParameterCount > 0, stringBuilder => stringBuilder.Append(',', typeParameterCount - 1)) + .AppendItems( + fullType.TypeMetadata.TypeParameters, + (builder, typeParameter) => + { + builder.If(!omitVariance && typeParameter.VarianceKind != VarianceKind.None, builder => builder.Append(GetVariance(typeParameter)).Append(' ')).Append(typeParameter.Name); + }, + separator) .Append('>'); } + else + { + stringBuilder.Append('<').Append(',', typeParameterCount - 1).Append('>'); + } } return stringBuilder; diff --git a/Source/Sundew.DiscriminatedUnions.TestData/Sundew.DiscriminatedUnions.TestData.csproj b/Source/Sundew.DiscriminatedUnions.TestData/Sundew.DiscriminatedUnions.TestData.csproj index 7aa57e1..2f352f6 100644 --- a/Source/Sundew.DiscriminatedUnions.TestData/Sundew.DiscriminatedUnions.TestData.csproj +++ b/Source/Sundew.DiscriminatedUnions.TestData/Sundew.DiscriminatedUnions.TestData.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 latest diff --git a/Source/Sundew.DiscriminatedUnions.Tester/IGenericOutParameter.cs b/Source/Sundew.DiscriminatedUnions.Tester/IGenericOutParameter.cs new file mode 100644 index 0000000..7811df2 --- /dev/null +++ b/Source/Sundew.DiscriminatedUnions.Tester/IGenericOutParameter.cs @@ -0,0 +1,12 @@ +namespace Sundew.DiscriminatedUnions.Tester; + +[DiscriminatedUnion(generatorFeatures: GeneratorFeatures.Segregate)] +public partial interface IGenericOutParameter + where T : notnull +{ + +} + + +public sealed record GenericOutParameter(T Value) : IGenericOutParameter + where T : notnull; \ No newline at end of file diff --git a/Source/Sundew.DiscriminatedUnions.Tester/Sundew.DiscriminatedUnions.Tester.csproj b/Source/Sundew.DiscriminatedUnions.Tester/Sundew.DiscriminatedUnions.Tester.csproj index 14b7dcb..7129fde 100644 --- a/Source/Sundew.DiscriminatedUnions.Tester/Sundew.DiscriminatedUnions.Tester.csproj +++ b/Source/Sundew.DiscriminatedUnions.Tester/Sundew.DiscriminatedUnions.Tester.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 false