Skip to content

Commit

Permalink
Added the MethodCall.TryReplaceVariableCreationWithAssignment() funct…
Browse files Browse the repository at this point in the history
…ionality for Wolverine. Bumps to 3.2
  • Loading branch information
jeremydmiller committed Oct 9, 2023
1 parent f0752fd commit d510764
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<VersionPrefix>3.1.1</VersionPrefix>
<VersionPrefix>3.2.0</VersionPrefix>
<LangVersion>10.0</LangVersion>
<Authors>Jeremy D. Miller;Babu Annamalai;Oskar Dudycz;Joona-Pekka Kokko</Authors>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
Expand Down
52 changes: 52 additions & 0 deletions src/CodegenTests/Codegen/MethodCallTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using JasperFx.CodeGeneration;
using JasperFx.CodeGeneration.Frames;
using JasperFx.CodeGeneration.Model;
using Microsoft.CodeAnalysis.FlowAnalysis;
using NSubstitute;
using Shouldly;
using Xunit;
Expand Down Expand Up @@ -311,6 +312,42 @@ public void return_type_for_method_returning_ValueTask_of_T()
MethodCall.For<MethodCallTarget>(x => x.ValueTaskString())
.ReturnType.ShouldBe(typeof(string));
}

[Fact]
public void try_to_assign_variable_to_void_method()
{
// Nothing happens, nothing blows up
var methodCall = MethodCall.For<MethodCallTarget>(x => x.Throw(null));
methodCall
.TryReplaceVariableCreationWithAssignment(new Variable(typeof(Ball)));

methodCall.ReturnVariable.ShouldBeNull();
}

[Fact]
public void try_to_assign_variable_to_exact_match()
{
var methodCall = MethodCall.For<MethodCallTarget>(x => x.Basketball());

var ball = new Variable(typeof(Basketball));
methodCall.TryReplaceVariableCreationWithAssignment(ball);

methodCall.ReturnVariable.ShouldBe(ball);
methodCall.ReturnAction.ShouldBe(ReturnAction.Assign);
}

[Fact]
public void try_to_assign_variable_within_tuple()
{
var methodCall = MethodCall.For<MethodCallTarget>(x => x.Sports());

var ball = new Variable(typeof(Basketball), "spalding");
methodCall.TryReplaceVariableCreationWithAssignment(ball);

var tuple = methodCall.ReturnVariable.ShouldBeOfType<ValueTypeReturnVariable>();
tuple.Inners[1].Inner.ShouldBeSameAs(ball);
tuple.Inners[1].Action.ShouldBe(ReturnAction.Assign);
}
}

public class Ball
Expand All @@ -327,6 +364,21 @@ public void Throw(Ball ball)
{
}

public Basketball Basketball()
{
return new Basketball();
}

public Ball CreateBall()
{
return new Ball();
}

public (Ball, Basketball) Sports()
{
return (new Ball(), new Basketball());
}

public void WithOuts(string in1, out string out1, out int out2)
{
out1 = "foo";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ public void override_variable_name_of_one_of_the_inners()
theCall.ReturnVariable.Usage.ShouldBe("(var mauve, var blue, var green)");
}

[Fact]
public void assign_variable_instead()
{
var color = new Variable(typeof(string), "color");
theCall.AssignResultTo(0, color);

theCall.ReturnVariable.Usage.ShouldBe("(color, var blue, var green)");
}

[Fact]
public void the_creates_new_of_applies_to_tuple_values()
{
Expand Down
40 changes: 40 additions & 0 deletions src/JasperFx.CodeGeneration/Frames/MethodCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,44 @@ public override string ToString()
{
return $"{nameof(HandlerType)}: {HandlerType}, {nameof(Method)}: {Method}";
}

/// <summary>
/// Assign the result of the supplied index within a value tuple return variable
/// </summary>
/// <param name="index"></param>
/// <param name="variable"></param>
public void AssignResultTo(int index, Variable variable)
{
if (ReturnVariable is ValueTypeReturnVariable tuple)
{
var inner = tuple.Inners[index].Inner;
creates.Remove(inner);

tuple.AssignResultTo(index, variable);
}
else
{
throw new InvalidOperationException("Return variable is not a tuple");
}


}

public void TryReplaceVariableCreationWithAssignment(Variable variable)
{
if (ReturnVariable == null) return;

if (ReturnVariable.VariableType == variable.VariableType)
{
AssignResultTo(variable);
}
else if (ReturnVariable is ValueTypeReturnVariable tuple)
{
var index = ArrayTools.IndexOf(tuple.Inners, v => v.Inner.VariableType == variable.VariableType);
if (index > -1)
{
AssignResultTo(index, variable);
}
}
}
}
18 changes: 15 additions & 3 deletions src/JasperFx.CodeGeneration/Model/ValueTypeReturnVariable.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
using System;
using System.Linq;
using JasperFx.CodeGeneration.Frames;
using JasperFx.Core;

namespace JasperFx.CodeGeneration.Model;

public class ValueTypeReturnVariable : Variable
{
private readonly Variable[] _inner;

public ValueTypeReturnVariable(Type returnType, Variable[] inner) : base(returnType)
{
_inner = inner;
Inners = inner.Select(x => new TupleVariable(x, ReturnAction.Initialize)).ToArray();
}

public override string Usage => "(" + _inner.Select(x => $"var {x.Usage}").Join(", ") + ")";
public override string Usage => "(" + Inners.Select(x => x.Usage()).Join(", ") + ")";

public TupleVariable[] Inners { get; }

public record TupleVariable(Variable Inner, ReturnAction Action)
{
public string Usage() => Action == ReturnAction.Initialize ? $"var {Inner.Usage}" : Inner.Usage;
}

public void AssignResultTo(int index, Variable variable)
{
Inners[index] = new TupleVariable(variable, ReturnAction.Assign);
}
}

0 comments on commit d510764

Please sign in to comment.