diff --git a/Directory.Build.props b/Directory.Build.props
index ecdb625..5faf412 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,7 +7,7 @@
JasperFx.Events, JasperFx.Events.SourceGenerator) set
$(JasperFxVersion) so they always release together. Bump this one
value to release the whole set. -->
- 2.2.0
+ 2.2.1
13
1570;1571;1572;1573;1574;1587;1591;1701;1702;1711;1735;0618
Jeremy D. Miller;Jaedyn Tonee
diff --git a/src/JasperFx.SourceGenerator/InputParserGenerator.cs b/src/JasperFx.SourceGenerator/InputParserGenerator.cs
index f7fa43b..74bbd6b 100644
--- a/src/JasperFx.SourceGenerator/InputParserGenerator.cs
+++ b/src/JasperFx.SourceGenerator/InputParserGenerator.cs
@@ -408,7 +408,7 @@ private static string GetConverterExpression(MemberParseInfo member)
"global::System.Guid" => "s => global::System.Guid.Parse(s)",
"global::System.DateTime" => "s => global::JasperFx.CommandLine.Internal.Conversion.DateTimeConverter.GetDateTime(s)",
"global::System.TimeSpan" => "s => global::JasperFx.CommandLine.Internal.Conversion.TimeSpanConverter.GetTimeSpan(s)",
- _ => $"new global::JasperFx.CommandLine.Internal.Conversion.Conversions().FindConverter(typeof({type}))!",
+ _ => $"s => ({type})new global::JasperFx.CommandLine.Internal.Conversion.Conversions().FindConverter(typeof({type}))!(s)",
};
}
diff --git a/src/JasperFx/CodeGeneration/DependencyGatherer.cs b/src/JasperFx/CodeGeneration/DependencyGatherer.cs
index 18a76f3..be2668a 100644
--- a/src/JasperFx/CodeGeneration/DependencyGatherer.cs
+++ b/src/JasperFx/CodeGeneration/DependencyGatherer.cs
@@ -14,39 +14,87 @@ internal class DependencyGatherer
public DependencyGatherer(IMethodVariables methodVariables, IList frames)
{
_methodVariables = methodVariables;
- Dependencies.OnMissing = frame => new List(findDependencies(frame).Distinct());
- Variables.OnMissing = v => new List(findDependencies(v).Distinct());
+ Dependencies.OnMissing = frame =>
+ {
+ // Iterative BFS replaces the original co-recursive yield iterators that lacked cycle
+ // protection and stack-overflowed on deep Frame/Variable graphs (e.g. Lamar/Wolverine's
+ // resolver code-gen). Variables encountered along the way are pinned into the Variables
+ // cache via Fill so MethodFrameArranger.findInjectedFields (which reads Variables.Keys())
+ // observes the same population the original recursive walk produced as a side effect.
+ var result = new List();
+ var seenFrames = new HashSet { frame };
+ var seenVariables = new HashSet();
+ Walk(frame, null, result, seenFrames, seenVariables, top: frame);
+ return result;
+ };
+ Variables.OnMissing = v =>
+ {
+ var result = new List();
+ var seenFrames = new HashSet();
+ var seenVariables = new HashSet { v };
+ Walk(null, v, result, seenFrames, seenVariables, top: null);
+ return result;
+ };
foreach (var frame in frames) Dependencies.FillDefault(frame);
}
-
- private IEnumerable findDependencies(Frame frame)
+ private void Walk(Frame? startFrame, Variable? startVariable, List result,
+ HashSet seenFrames, HashSet seenVariables, Frame? top)
{
- frame.ResolveVariables(_methodVariables);
+ var frameQueue = new Queue();
+ var variableQueue = new Queue();
+ if (startFrame != null) frameQueue.Enqueue(startFrame);
+ if (startVariable != null) variableQueue.Enqueue(startVariable);
- foreach (var dependency in frame.Dependencies)
+ while (frameQueue.Count > 0 || variableQueue.Count > 0)
{
- yield return dependency;
+ while (frameQueue.Count > 0)
+ {
+ var f = frameQueue.Dequeue();
+ f.ResolveVariables(_methodVariables);
- foreach (var child in Dependencies[dependency]) yield return child;
- }
+ foreach (var dep in f.Dependencies)
+ {
+ if (seenFrames.Add(dep))
+ {
+ if (!ReferenceEquals(dep, top)) result.Add(dep);
+ frameQueue.Enqueue(dep);
+ }
+ }
- foreach (var variable in frame.Uses)
- foreach (var dependency in Variables[variable])
- yield return dependency;
- }
+ foreach (var v in f.Uses)
+ {
+ if (seenVariables.Add(v))
+ {
+ // Pin the key so findInjectedFields' Variables.Keys() lookup sees it. The
+ // value here is a placeholder; the next caller to read Variables[v]
+ // through the indexer triggers a fresh BFS via OnMissing.
+ Variables.Fill(v, EmptyList);
+ variableQueue.Enqueue(v);
+ }
+ }
+ }
- private IEnumerable findDependencies(Variable variable)
- {
- if (variable.Creator != null)
- {
- yield return variable.Creator;
- foreach (var frame in Dependencies[variable.Creator]) yield return frame;
- }
+ if (variableQueue.Count == 0) break;
+ var variable = variableQueue.Dequeue();
+
+ if (variable.Creator != null && seenFrames.Add(variable.Creator))
+ {
+ if (!ReferenceEquals(variable.Creator, top)) result.Add(variable.Creator);
+ frameQueue.Enqueue(variable.Creator);
+ }
- foreach (var dependency in variable.Dependencies)
- foreach (var frame in Variables[dependency])
- yield return frame;
+ foreach (var d in variable.Dependencies)
+ {
+ if (seenVariables.Add(d))
+ {
+ Variables.Fill(d, EmptyList);
+ variableQueue.Enqueue(d);
+ }
+ }
+ }
}
-}
\ No newline at end of file
+
+ private static readonly List EmptyList = new(0);
+}