Skip to content

Commit

Permalink
Fixed variance on generic interface unions
Browse files Browse the repository at this point in the history
=> release
  • Loading branch information
hugener committed Oct 26, 2024
1 parent b59ec88 commit 702ab95
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<CodeAnalysisRuleSet></CodeAnalysisRuleSet>
<IsPackable>false</IsPackable>
<RuntimeIdentifiers>win10-x64;osx.10.12-x64;debian.8-x64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Keywords = new HashSet<string>
{
"abstract",
Expand Down Expand Up @@ -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:
Expand All @@ -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)))
Expand All @@ -213,9 +203,9 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua
elementAttributeName,
elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias,
true,
new TypeMetadata(null, elementFullName, ImmutableArray<TypeParameter>.Empty));
new TypeMetadata(elementFullName, ImmutableArray<TypeParameter>.Empty));
case ITypeParameterSymbol typeParameterSymbol:
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, string.Empty, ImmutableArray<TypeParameter>.Empty));
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(string.Empty, ImmutableArray<TypeParameter>.Empty));
default:
throw new System.ArgumentOutOfRangeException(nameof(typeSymbol));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Constraints);
internal readonly record struct TypeParameter(string Name, VarianceKind VarianceKind, ValueArray<string> Constraints);
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeParameter> TypeParameters);
internal readonly record struct TypeMetadata(string FullName, ValueArray<TypeParameter> TypeParameters);
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -39,8 +40,10 @@ internal static class StringBuilderExtensions
private const string SummaryStart = "/// <summary>";
private const string SummaryEnd = "/// </summary>";
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)
{
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//HintName: Sundew.DiscriminatedUnions.Tester.IGenericOutParameterExtensions{T}.generated.cs
#nullable enable

namespace Sundew.DiscriminatedUnions.Tester
{
/// <summary>
/// Segregation extension method for IGenericOutParameter.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCode]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.3.0.0")]
public static partial class IGenericOutParameterExtensions
{
/// <summary>
/// Segregates the items in the specified enumerable by type.
/// </summary>
/// <param name="iGenericOutParameters">The iGenericOutParameters.</param>
/// <returns>A new IGenericOutParameterSegregation.</returns>
public static IGenericOutParameterSegregation<T> Segregate<T>(this System.Collections.Generic.IEnumerable<global::Sundew.DiscriminatedUnions.Tester.IGenericOutParameter<T>> iGenericOutParameters)
where T : notnull
{
var genericOutParameters = new System.Collections.Generic.List<global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<T>>();

foreach (var value in iGenericOutParameters)
{
switch (value)
{
case global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<T> genericOutParameter:
genericOutParameters.Add(genericOutParameter);
break;
}
}

return new global::Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation<T>(genericOutParameters);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//HintName: Sundew.DiscriminatedUnions.Tester.IGenericOutParameterSegregation{T}.generated.cs
#nullable enable

namespace Sundew.DiscriminatedUnions.Tester
{
/// <summary>
/// Contains individual lists of the different cases of the discriminated union IGenericOutParameter.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCode]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.3.0.0")]
public sealed partial class IGenericOutParameterSegregation<T>
where T : notnull
{
internal IGenericOutParameterSegregation(System.Collections.Generic.IReadOnlyList<global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<T>> genericOutParameters)
{
this.GenericOutParameters = genericOutParameters;
}

/// <summary>
/// Gets the GenericOutParameters.
/// </summary>
/// <returns>The GenericOutParameters.</returns>
public System.Collections.Generic.IReadOnlyList<global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<T>> GenericOutParameters { get; }
}
}
Original file line number Diff line number Diff line change
@@ -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<out T>
where T : notnull
#pragma warning restore SA1601
{
/// <summary>
/// Factory method for the GenericOutParameter case.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A new GenericOutParameter.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<>))]
[global::System.Diagnostics.DebuggerNonUserCode]
public static global::Sundew.DiscriminatedUnions.Tester.IGenericOutParameter<T> GenericOutParameter(T value)
=> new global::Sundew.DiscriminatedUnions.Tester.GenericOutParameter<T>(value);
}
}
24 changes: 7 additions & 17 deletions Source/Sundew.DiscriminatedUnions.Generator/CodeAnalysisHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Keywords = new HashSet<string>
{
"abstract",
Expand Down Expand Up @@ -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:
Expand All @@ -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)))
Expand All @@ -213,9 +203,9 @@ public static FullType GetFullType(this ITypeSymbol typeSymbol, bool useFullyQua
elementAttributeName,
elementIsShortNameAlias ? string.Empty : GlobalAssemblyAlias,
true,
new TypeMetadata(null, elementFullName, ImmutableArray<TypeParameter>.Empty));
new TypeMetadata(elementFullName, ImmutableArray<TypeParameter>.Empty));
case ITypeParameterSymbol typeParameterSymbol:
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(null, string.Empty, ImmutableArray<TypeParameter>.Empty));
return new FullType(typeParameterSymbol.MetadataName, string.Empty, string.Empty, string.Empty, false, new TypeMetadata(string.Empty, ImmutableArray<TypeParameter>.Empty));
default:
throw new System.ArgumentOutOfRangeException(nameof(typeSymbol));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> Constraints);
internal readonly record struct TypeParameter(string Name, VarianceKind VarianceKind, ValueArray<string> Constraints);
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeParameter> TypeParameters);
internal readonly record struct TypeMetadata(string FullName, ValueArray<TypeParameter> TypeParameters);
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 702ab95

Please sign in to comment.