-
-
Notifications
You must be signed in to change notification settings - Fork 264
Full AOT Support for .NET 8+ #582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Without having a close look yet myself…any hunches on why CI fails? |
|
Probably because the build might need to be adjusted for the generators. AOT has additional requirements that might need to be installed for the build. I'll take a look and drop another PR for the fix. But it should compile locally, and I can post the commands you need to make sure the right VC++ packages are installed on Windows to be able to run the AOT build. |
|
Fixed the main build issue. Improving code coverage and working on getting the docs fixed now. |
- DocFX fixes for the generators, which are not a public API
Added tests for: - CommandMetadataRegistry generic methods (Register<T>, TryGetProvider<T>, HasMetadata<T>) - ErrorExecuteHandler (constructor, IsAsync, InvokeAsync) - CommandLineApplicationWithModel (constructor, Model property, IModelAccessor) - OptionAttributeConventionBase inherited option handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added tests for: - CommandAttribute.ClusterOptionsWasSet and UnrecognizedArgumentHandlingWasSet - CommandAttribute.Configure with explicit vs default values - Convention AOT code paths (generated metadata setters) - RemainingArgsPropertyConvention with SpecialPropertiesMetadata - ParentPropertyConvention with SpecialPropertiesMetadata - SubcommandPropertyConvention with SpecialPropertiesMetadata - ConventionContext.MetadataProvider and HasGeneratedMetadata - CommandAttributeConvention with CommandMetadata - SubcommandAttributeConvention with SubcommandMetadata 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@natemcmaster I think this is ready for you to review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good so far. The fact that I see very few changes to existing unit tests and all tests are now passing CI gives me higher confidence we're on track to release this feature.
I'm only halfway done reading through the code. 11k is a lot and I haven't yet deferred review responsibility to Claude. That said, I wanted to leave you some initial feedback as I'm making progress.
Remaining review steps:
- Review changes to src/CommandLineUtils/Conventions
- Review new code in src/CommandLineUtils/SourceGeneration and matching tests
- Review aot-plan.md for remaining work (like docs or release notes)
|
Claude generated the following feedback: Code Review for PR #582: Full AOT Support for .NET 8+Thanks for this substantial contribution! This is a significant architectural change to enable Native AOT compilation. I've reviewed the key code changes and identified a few potential issues worth discussing. Issue 1: MakeGenericMethod still used in SubcommandAttributeConventionFile: var genericType = typeof(CommandLineApplication<>).MakeGenericType(subcommandType);
var constructor = genericType.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new[] { typeof(CommandLineApplication), typeof(string) },
null);Suggested fix: Consider using the Issue 2: Potential null reference in GeneratedModelFactory when DI failsFile: Code: sb.AppendLine($"{indent} throw new InvalidOperationException(\"Unable to create instance of {info.ClassName}. No services registered for constructor parameters.\");");Why it matters: The error message says "No services registered" but the actual problem could be that no Suggested fix: Differentiate the error messages:
Issue 3: Subcommand metadata provider may throw unhelpful exceptionFile: sb.AppendLine($"{indent} MetadataProviderFactory = () => CommandMetadataRegistry.TryGetProvider(typeof({sub.TypeName}), out var p) ? p : throw new InvalidOperationException(\"No metadata provider for \" + typeof({sub.TypeName}))");Why it matters: In AOT scenarios, if the subcommand class wasn't processed by the source generator (e.g., it's in a different assembly without the generator), the user gets a runtime error with no guidance on how to fix it. Suggested fix: Consider falling back to Issue 4: Async execute handler doesn't await Task before checking return typeFile: Suggested fix: For sync methods, consider returning public Task<int> InvokeAsync(object model, CommandLineApplication app, CancellationToken cancellationToken)
{
var typedModel = (ClassName)model;
typedModel.OnExecute();
return Task.FromResult(0);
}Other Observations (not blocking)
The changes look architecturally sound overall. The dual-mode approach (generated + reflection fallback) is a solid pattern for maintaining backward compatibility while enabling AOT. The issues identified above are primarily about improving error messages and ensuring the AOT path is fully reflection-free. |
- Rename CommandInfo to CommandData for naming consistency with other POCOs - Extract ConstructorParameterData to its own file - Delete obsolete update_generator.ps1 patching script - Improve error messages in GenerateModelFactory to distinguish between missing IServiceProvider vs unregistered services - Add fallback to DefaultMetadataResolver for subcommand metadata providers - Use Task.FromResult for sync OnExecute methods to avoid async warnings - Add [DynamicallyAccessedMembers] annotation to SubcommandAttributeConvention for AOT compatibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
OK, I addressed all of the issues mentioned. The Claude Code review failed, and GitHub Copilot said this about the fix:
|
|
Yeah, it looks like this is a limitation anthropics/claude-code-action#339. I'm not sure how to configure this to work, so I will just disable it on PRs for now. |
|
Thanks for this contribution @robertmclaws ! I reviewed the changes, with some assistance from claude. It found a couple minor issues, but I think the core pieces are in place. I'd like to make a beta release to nuget and start publicizing to see if we can have more people test it out. |
Bug 1 - Value type constructor parameters:
- Changed from 'as {TypeName}' to checking service != null then casting
- Avoids CS0077 compiler error with non-nullable value types
- Generated code now: var service = GetService(...); if (service != null) return new T((Type)service!)
Bug 2 - Nullable array RemainingArguments:
- Changed from string comparison to IArrayTypeSymbol type check
- Fixes issue where 'string[]?' didn't match 'string[]' string comparison
- Now correctly generates ToArray() conversion for all array types
Also added System.Linq using to generated code for ToArray() support.
Fixes #582 review issues
## Summary Fixes critical and high-severity bugs in the source generator that were identified during review of #582. ## Issues Fixed ### Bug 1: Value Type Constructor Parameters (Critical - CS0077) **Problem:** Generated code used `as` operator with non-nullable value types: ```csharp var p0_0 = _services.GetService(typeof(int)) as int; // CS0077 compiler error ``` **Fix:** Check service object for null, then use direct cast: ```csharp var service0_0 = _services.GetService(typeof(int)); if (service0_0 != null) return new T((int)service0_0!); ``` **Impact:** Any command with value type constructor parameters (int, bool, etc.) would fail to compile with CS0077. ### Bug 2: Nullable Array RemainingArguments (High Severity) **Problem:** Used fragile string comparison for type detection: ```csharp if (sp.RemainingArgumentsPropertyType == "string[]") // Fails for "string[]?" ``` **Fix:** Use actual type analysis with `IArrayTypeSymbol`: ```csharp info.SpecialProperties.RemainingArgumentsIsArray = property.Type is IArrayTypeSymbol; ``` **Impact:** Properties like `string[]?` would use wrong code path, causing `InvalidCastException` at runtime. ### Additional Fixes - Added `System.Linq` using to generated code for `ToArray()` support - Fixed `CommandData` property name to `CommandInfo` to match interface - Organized Claude planning documents in `.claude/plans/` ## Test Coverage Added comprehensive tests demonstrating both bugs: 1. **GeneratorBugReproduction/** - Compilation test project that demonstrates bugs would cause CS0077 2. **GeneratedModelFactoryTests.cs** - Unit tests for value type handling patterns 3. **SpecialPropertiesMetadataTests.cs** - Tests for array type conversion logic All tests now pass ✅
Implements #581