Skip to content

Latest commit

 

History

History
47 lines (35 loc) · 6.09 KB

File metadata and controls

47 lines (35 loc) · 6.09 KB

AOT support matrix

Reactor's core framework targets .NET native AOT. The repo sets IsAotCompatible=true and treats the IL2*/IL3* analyzer warnings as errors on the core library, so trimming/AOT regressions can't merge silently. The tests/stress_perf/StressPerf.Reactor benchmark harness publishes Reactor with PublishAot=true on every CI build that runs perf — that's the canary for the framework's AOT viability.

But not every subsystem is AOT-clean. Some features rely on reflection in ways that can't yet be expressed without a source generator, and they sit behind unconditional trim suppressions. The suppressions silence the analyzer; at runtime, the affected code paths will throw under AOT if they're invoked.

This page enumerates what works, what doesn't, and what's planned. If you publish your app with PublishAot=true, you're responsible for staying inside the green column.

What works under AOT

  • Core reconciler — virtual element tree, diffing, mount/update, keyed reconciliation, element pooling.
  • DSL & elements — factory methods, fluent modifiers.
  • HooksUseState, UseReducer, UseEffect, UseMemo, UseRef, UseCallback. (See note on UseObservable below.)
  • Flex layout — Yoga port is pure C#, no reflection.
  • Charting (D3) — algorithm port is pure C#.
  • Markdown — md4c-backed parser and renderer.
  • Commanding — command records, focus-scoped accelerators.
  • Animation — compositor-layer transitions, keyframes.
  • ThemingThemeRef tokens, style caching.
  • Markdown / Localization (read path)IStringLoc/Loc.X.Y lookups generated by Reactor.Localization.Generator are AOT-clean. Source-generated, no runtime reflection.

What does not work under AOT (today)

These subsystems compile cleanly with IsAotCompatible=true (the warnings are suppressed), but the suppressions cover real reflection that will throw at runtime under PublishAot=true. Don't rely on them in an AOT-published app until they're rebuilt on source generators.

Subsystem What breaks Tracking
Devtools / MCP server Assembly.GetTypes for component discovery, reflection-based hook inspection in DevtoolsStateTool, reflection-based method invocation in DevtoolsFireTool, DependencyProperty enumeration in DevtoolsPropertyTools, JsonSerializer for MCP request/response. The whole devtools surface (/--devtools, /--mcp-stdio) is reflection-driven. Issue #70
PropertyGrid auto-discovery TypeRegistry.Resolve, ReflectionTypeMetadataProvider walk public properties, build init-only setters, and instantiate editors via Activator.CreateInstance. Manually-registered metadata is fine; auto-discovery from a runtime type is not. Issue #70
PropertyGrid array editor Array.CreateInstance is annotated RequiresDynamicCode. Array-typed property editors won't work AOT. Issue #70
DataGrid AutoColumns<T> Reflects over T's public properties via TypeRegistry. The T parameter is annotated [DynamicallyAccessedMembers(PublicProperties)] so the trimmer keeps the members, but AutoColumns ultimately funnels into TypeRegistry.Resolve, which is RequiresUnreferencedCode. Use explicit Column<T,V>(…) definitions instead. Issue #70
UseObservable on POCOs ObservableTreeTracker walks public properties via reflection to subscribe to INPC. Observables built explicitly (Observable<T>, IObservableCollection) are fine; the implicit-INPC path is not. Issue #70
Form validation FormField's default editor resolution goes through TypeRegistry. Same caveat as PropertyGrid. Issue #70
Navigation state JSON NavigationHandle serializes deep-link state via JsonSerializer without a source-generated context. Custom types that ride through navigation state will fail to serialize under AOT. Issue #70
Component discovery (ReactorApp.Run<TApp> reflection paths) The instantiation of TApp itself is annotated and works. The devtools-only --list-components enumeration scans Assembly.GetTypes; that path is gated to non-AOT builds. Issue #70
Theme resource lookup (Theme.X, ThemeRef.Resolve) ThemeRef.Resolve walks Application.Current.Resources + its merged/theme dictionaries. The token records (Theme.Accent, Theme.PrimaryText, …) construct fine, but at runtime the XamlControlsResources entries that ReactorApplication.xaml brings in aren't fully populated under AOT — Resolve returns null for keys that exist under the JIT. Brushes applied via .Foreground(Theme.X) will fall back to control defaults. Issue #70
XAML-metadata-dependent controls (NavigationView, TabView, TemplateBinding) A subset of WinUI controls and the XAML-template parser need richer IXamlMetadataProvider data than what's reachable through trimmed AOT publish. NavigationView / TabView won't even reach Mount in this state, and {TemplateBinding} against custom DPs can't resolve the DP descriptor (see issue #142 reproductions). Use simpler containers under AOT. Issue #70

Conventions

  • The library compiles AOT-clean. Builds of Reactor.csproj produce zero IL2*/IL3* warnings. New code that reaches for reflection must either be source-generated, annotated with DynamicallyAccessedMembers, or — as a last resort — gated behind [RequiresUnreferencedCode] / [RequiresDynamicCode] so consumers see the warning at the call site.
  • Suppressions are temporary. Every [UnconditionalSuppressMessage("Trimming", ...)] or ("AOT", ...) in this repo is a TODO. The justification field names the reflection use; tracking is folded into issue #70.
  • The benchmark canary. tests/stress_perf/StressPerf.Reactor (and the StressPerf.Direct/ReactorGrid siblings) set PublishAot=true. If they stop publishing, an AOT regression has landed in the framework.

When in doubt

If you need a feature listed in the "does not work" table and you're publishing AOT, file an issue against #70 with your scenario. The fix in most cases is a source generator pass; what gets prioritized is driven by who's hitting the wall.