Skip to content

Commit

Permalink
Optional default implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
2A5F committed Jan 8, 2024
1 parent e638df7 commit 3080b0a
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,17 @@ public static UnionAttr FromData(AttributeData data, List<Diagnostic> diagnostic
}
}

public class TemplateStructUnion
(GenBase GenBase, string Name, UnionAttr Attr, bool ReadOnly, bool IsClass, List<UnionCase> Cases,
bool AnyGeneric) : ATemplate(GenBase)
public record struct UnionGenerateMethod(bool genToString, bool genEquals, bool genCompareTo);

public class TemplateStructUnion(
GenBase GenBase,
string Name,
UnionAttr Attr,
bool ReadOnly,
bool IsClass,
List<UnionCase> Cases,
bool AnyGeneric,
UnionGenerateMethod genMethods) : ATemplate(GenBase)
{
public const string AggressiveInlining =
"[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]";
Expand Down Expand Up @@ -101,12 +109,19 @@ protected override void DoGen()

sb.AppendLine(GenBase.Target.Code);
sb.AppendLine($" : global::Sera.TaggedUnion.ITaggedUnion");
sb.AppendLine($" , global::System.IEquatable<{TypeName}>");
sb.AppendLine($" , global::System.IComparable<{TypeName}>");
sb.AppendLine($"#if NET7_0_OR_GREATER");
sb.AppendLine($" , global::System.Numerics.IEqualityOperators<{TypeName}, {TypeName}, bool>");
sb.AppendLine($" , global::System.Numerics.IComparisonOperators<{TypeName}, {TypeName}, bool>");
sb.AppendLine($"#endif");
if (genMethods.genEquals)
sb.AppendLine($" , global::System.IEquatable<{TypeName}>");
if (genMethods.genCompareTo)
sb.AppendLine($" , global::System.IComparable<{TypeName}>");
if (genMethods.genEquals || genMethods.genCompareTo)
{
sb.AppendLine($"#if NET7_0_OR_GREATER");
if (genMethods.genEquals)
sb.AppendLine($" , global::System.Numerics.IEqualityOperators<{TypeName}, {TypeName}, bool>");
if (genMethods.genCompareTo)
sb.AppendLine($" , global::System.Numerics.IComparisonOperators<{TypeName}, {TypeName}, bool>");
sb.AppendLine($"#endif");
}
sb.AppendLine("{");

sb.AppendLine(ReadOnly ? $" private{@readonly} {impl_name} _impl;" : $" private {impl_name} _impl;");
Expand Down Expand Up @@ -305,7 +320,7 @@ private void GenImpl(string name, string tags_name)
private void GenMakeEmpty()
{
sb.AppendLine($" {AggressiveInlining}");
sb.AppendLine($" public static {TypeName} Make() => default;");
sb.AppendLine($" public static {TypeName} Make() => new(default(__impl_)!);");
}

private void GenMake(string impl_name, string tags_name)
Expand Down Expand Up @@ -438,6 +453,8 @@ void GenField(bool get)

private void GenEquatable(string tags_name)
{
if (!genMethods.genEquals) return;

var q = IsClass && TypeName.Last() != '?' ? "?" : string.Empty;

#region Equals
Expand Down Expand Up @@ -486,7 +503,8 @@ private void GenEquatable(string tags_name)
sb.AppendLine();

sb.AppendLine($" {AggressiveInlining}");
sb.AppendLine($" public static bool operator ==({TypeName}{q} left, {TypeName}{q} right) => Equals(left, right);");
sb.AppendLine(
$" public static bool operator ==({TypeName}{q} left, {TypeName}{q} right) => Equals(left, right);");
sb.AppendLine($" {AggressiveInlining}");
sb.AppendLine(
$" public static bool operator !=({TypeName}{q} left, {TypeName}{q} right) => !Equals(left, right);");
Expand All @@ -496,8 +514,10 @@ private void GenEquatable(string tags_name)

private void GenComparable(string tags_name)
{
if (!genMethods.genCompareTo) return;

var q = IsClass && TypeName.Last() != '?' ? "?" : string.Empty;

#region CompareTo

sb.AppendLine($" {AggressiveInlining}");
Expand Down Expand Up @@ -537,6 +557,7 @@ private void GenComparable(string tags_name)

private void GenToStr(string tags_name)
{
if (!genMethods.genToString) return;
sb.AppendLine($" {AggressiveInlining}");
sb.AppendLine($" public{@readonly} override string ToString() => this.Tag switch");
sb.AppendLine($" {{");
Expand Down
31 changes: 23 additions & 8 deletions Sera.TaggedUnion.Analyzers/Generators/UnionGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,28 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var nameWrap = symbol.WrapName();
var readOnly = symbol.IsReadOnly;
var isClass = syntax is ClassDeclarationSyntax;
return (syntax, semanticModel, union_attr, readOnly, isClass, rawFullName, nameWraps, nameWrap,
AlwaysEq.Create(diagnostics));
var hasToString = symbol.GetMembers("ToString")
.Where(s => s is IMethodSymbol)
.Cast<IMethodSymbol>()
.Any(s => s.TypeParameters.Length == 0 && s.Parameters.Length == 0);
var NamedArguments = attr.NamedArguments.ToDictionary(a => a.Key, a => a.Value);
var genToString = NamedArguments.TryGetValue("GenerateToString", out var _GenerateToString)
? (bool)_GenerateToString.Value!
: !hasToString;
var genEquals = !NamedArguments.TryGetValue("GenerateEquals", out var _GenerateEquals) ||
(bool)_GenerateEquals.Value!;
var genCompareTo = !NamedArguments.TryGetValue("GenerateCompareTo", out var _GenerateCompareTo) ||
(bool)_GenerateCompareTo.Value!;
var genMethods = new UnionGenerateMethod(genToString, genEquals, genCompareTo);
return (syntax, semanticModel, union_attr, readOnly, isClass, genMethods,
rawFullName, nameWraps, nameWrap, AlwaysEq.Create(diagnostics));
}
)
.Combine(context.CompilationProvider)
.Select(static (input, _) =>
{
var ((syntax, semanticModel, union_attr, readOnly, isClass, rawFullName, nameWraps, nameWrap,
diagnostics),
compilation) =
var ((syntax, semanticModel, union_attr, readOnly, isClass, genMethods, rawFullName, nameWraps,
nameWrap, diagnostics), compilation) =
input;
var nullable = compilation.Options.NullableContextOptions;
var usings = new HashSet<string>();
Expand Down Expand Up @@ -153,20 +165,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
}
var name = syntax.Identifier.ToString();
return (name, union_attr, readOnly, isClass, cases, any_generic, genBase, diagnostics);
return (name, union_attr, readOnly, isClass, cases, any_generic, genMethods, genBase, diagnostics);
});

context.RegisterSourceOutput(sources, static (ctx, input) =>
{
var (name, union_attr, readOnly, isClass, cases, any_generic, genBase, diagnostics) = input;
var (name, union_attr, readOnly, isClass, cases, any_generic, genMethods, genBase, diagnostics) = input;
if (diagnostics.Value.Count > 0)
{
foreach (var diagnostic in diagnostics.Value)
{
ctx.ReportDiagnostic(diagnostic);
}
}
var code = new TemplateStructUnion(genBase, name, union_attr, readOnly, isClass, cases, any_generic).Gen();
var code = new TemplateStructUnion(
genBase, name, union_attr, readOnly, isClass, cases, any_generic, genMethods
)
.Gen();
var sourceText = SourceText.From(code, Encoding.UTF8);
var rawSourceFileName = genBase.FileFullName;
var sourceFileName = $"{rawSourceFileName}.union.g.cs";
Expand Down
30 changes: 28 additions & 2 deletions Sera.TaggedUnion/Attrs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,35 @@ public sealed class UnionAttribute : Attribute
public string ExternalTagsName { get; set; } = "{0}Tags";
/// <summary>The underlying type of the Tags enum, the smallest required type is used by default</summary>
public Type? TagsUnderlying { get; set; }
/// <summary>
/// Whether to generate override of <see cref="object.ToString()"/>
/// </summary>
public bool GenerateToString { get; set; } = true;
#if NET7_0_OR_GREATER
/// <summary>
/// Whether to generate override of <see cref="object.Equals(object)"/>, <see cref="object.GetHashCode()"/>,
/// and implementation of <see cref="IEquatable{T}"/>, <see cref="System.Numerics.IEqualityOperators{A,B,C}"/>
/// </summary>
#else
/// <summary>
/// Whether to generate override of <see cref="object.Equals(object)"/>, <see cref="object.GetHashCode()"/>,
/// and implementation of <see cref="IEquatable{T}"/>
/// </summary>
#endif
public bool GenerateEquals { get; set; } = true;
#if NET7_0_OR_GREATER
/// <summary>
/// Whether to generate implementation of <see cref="IComparable{T}"/>, <see cref="System.Numerics.IComparisonOperators{A,B,C}"/>
/// </summary>
#else
/// <summary>
/// Whether to generate implementation of <see cref="IComparable{T}"/>
/// </summary>
#endif
public bool GenerateCompareTo { get; set; } = true;
}

[AttributeUsage(AttributeTargets.Interface, Inherited = false)]
[AttributeUsage(AttributeTargets.Interface)]
public sealed class UnionTemplateAttribute : Attribute;

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
Expand Down Expand Up @@ -48,4 +74,4 @@ public sealed class UnionSymbolAttribute : Attribute
/// parameter, <see cref="IsReferenceType"/> and <see cref="IsValueType"/> will both return false.
/// </summary>
public MayBool IsValueType { get; set; }
}
}
4 changes: 2 additions & 2 deletions Sera.TaggedUnion/Sera.TaggedUnion.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AssemblyName>Sera.Union</AssemblyName>
<RootNamespace>Sera.TaggedUnion</RootNamespace>
<Version>0.6.0</Version>
<Version>0.7.0</Version>
<Description>Tagged union for c#</Description>
<PackageProjectUrl>https://github.com/sera-net/Sera.Union</PackageProjectUrl>
<RepositoryUrl>https://github.com/sera-net/Sera.Union</RepositoryUrl>
Expand Down
4 changes: 2 additions & 2 deletions Sera.Union.Utilities/Sera.Union.Utilities.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AssemblyName>Sera.Union.Utilities</AssemblyName>
<RootNamespace>Sera.TaggedUnion.Utilities</RootNamespace>
<Version>0.6.0</Version>
<Version>0.7.0</Version>
<Description>Tagged union for c#</Description>
<PackageProjectUrl>https://github.com/sera-net/Sera.Union</PackageProjectUrl>
<RepositoryUrl>https://github.com/sera-net/Sera.Union</RepositoryUrl>
Expand Down
6 changes: 6 additions & 0 deletions Tests/Unions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,9 @@ private interface Template
(int a, string b) G();
}
}

[Union(GenerateEquals = false, GenerateCompareTo = false)]
public partial class Union10
{
public override string ToString() => "Fuck";
}

0 comments on commit 3080b0a

Please sign in to comment.