Skip to content
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

Warnings and errors when publishing a .NET 8 app as NativeAOT #367

Open
Numpsy opened this issue Nov 5, 2023 · 10 comments
Open

Warnings and errors when publishing a .NET 8 app as NativeAOT #367

Numpsy opened this issue Nov 5, 2023 · 10 comments

Comments

@Numpsy
Copy link
Collaborator

Numpsy commented Nov 5, 2023

This is a sort of followup to #281, but with a few FuncUI specific warnings in the build that might have local solutions, so -

I tried updating a FuncUI app to .NET 8 and publishing as NativeAOT with the RC2 SDK.
There are alas loads of warnings from FSharp.Core that are outside our control, but also these ones from FuncUI:

4>Avalonia.FuncUI.VirtualDom.Patcher.patchProperty(AvaloniaObject,Delta.PropertyDelta): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperty(String)'. The return value of method 'System.Object.GetType()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
4>Avalonia.FuncUI.VirtualDom.Patcher.patchProperty(AvaloniaObject,Delta.PropertyDelta): 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The return value of method 'System.Reflection.PropertyInfo.PropertyType.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
4>Avalonia.FuncUI.VirtualDom.Patcher.create(Delta.ViewDelta): 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' in call to 'System.Activator.CreateInstance(Type,Object[])'. The field 'Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.ViewType@' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
4>Avalonia.FuncUI.VirtualDom.Patcher.create(Delta.ViewDelta): 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicParameterlessConstructor' in call to 'System.Activator.CreateInstance(Type)'. The field 'Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.ViewType@' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

and then this happens at runtime:

Unhandled Exception: System.MissingMethodException: No parameterless constructor defined for type 'Avalonia.FuncUI.Component'.
   at System.ActivatorImplementation.CreateInstance(Type, BindingFlags, Binder, Object[], CultureInfo, Object[]) + 0x34b
   at Avalonia.FuncUI.VirtualDom.Patcher.create(Delta.ViewDelta) + 0x5e
   at Avalonia.FuncUI.VirtualDom.Patcher.patch_avalonia@167(FSharpOption`1, AvaloniaObject, AvaloniaProperty) + 0x72
   at Avalonia.FuncUI.VirtualDom.Patcher.patchContentSingle(AvaloniaObject, Types.Accessor, FSharpOption`1) + 0x82
   at Avalonia.FuncUI.VirtualDom.Patcher.create(Delta.ViewDelta) + 0x145
   at Avalonia.FuncUI.VirtualDom.VirtualDom.updateBorderRoot(Border, FSharpOption`1, FSharpOption`1) + 0x176
   at Avalonia.FuncUI.Component.UIThreadUpdate() + 0x6a
   at Avalonia.StyledElement.InitializeIfNeeded() + 0x2a
   at Avalonia.Controls.Control.OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs) + 0x8d
   at Avalonia.Visual.SetVisualParent(Visual) + 0xe5
   at Avalonia.Visual.SetVisualParent(IList, Visual) + 0x6c
   at Avalonia.Collections.AvaloniaList`1.NotifyAdd(T, Int32) + 0x72
   at Avalonia.Controls.Presenters.ContentPresenter.UpdateChild(Object) + 0x1c7
   at Avalonia.Layout.Layoutable.MeasureCore(Size) + 0x12e
   at Avalonia.Layout.Layoutable.Measure(Size) + 0xf0
   at Avalonia.Layout.LayoutHelper.MeasureChild(Layoutable, Size, Thickness) + 0xa0
   at Avalonia.Controls.Primitives.VisualLayerManager.MeasureOverride(Size) + 0xb4
   at Avalonia.Layout.Layoutable.MeasureCore(Size) + 0x19f
   at Avalonia.Layout.Layoutable.Measure(Size) + 0xf0
   at Avalonia.Layout.Layoutable.MeasureOverride(Size) + 0x7f
   at Avalonia.Layout.Layoutable.MeasureCore(Size) + 0x19f
   at Avalonia.Layout.Layoutable.Measure(Size) + 0xf0
   at Avalonia.Layout.Layoutable.MeasureOverride(Size) + 0x7f
   at Avalonia.Controls.Window.MeasureOverride(Size) + 0x1d1
   at Avalonia.Controls.WindowBase.MeasureCore(Size) + 0x5c
   at Avalonia.Layout.Layoutable.Measure(Size) + 0xf0
   at Avalonia.Layout.LayoutManager.Measure(Layoutable) + 0xc2
   at Avalonia.Layout.LayoutManager.ExecuteInitialLayoutPass() + 0x27
   at Avalonia.Controls.Window.ShowCore(Window) + 0x1f9
   at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.ShowMainWindow() + 0x1b
   at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[]) + 0x139
   at PackageViewer!<BaseAddress>+0xf6d860

Which suggests that the existing DynamicallyAccessedMembers attributes aren't covering all required cases.

Also, some of this might be hitting the existing TODO here about not using reflection:

// TODO: get rid of reflection here

@JaggerJo
Copy link
Member

JaggerJo commented Nov 5, 2023

Hey @Numpsy 👋

Looks like the DynamicMemberAccess attribute was completely missing for components.

b0aa279

@Numpsy
Copy link
Collaborator Author

Numpsy commented Nov 5, 2023

Ok, will give it another go with that change later.

On a related note, the use of Linq.Expression at https://github.com/fsprojects/Avalonia.FuncUI/blob/b0aa279c9760a2be2417230aad267a499bec2d47/src/Avalonia.FuncUI/DataTemplateView.fs#L16C1-L16C1 seems to cause problems for the trimmer too (like, it can't see what the delegate given to DataTemplateView is doing and can trim out things that are used by it).
I'm not sure if that one can be fixed with a central annotation (A DynamicDependency attribute at the call site can fix some of the issues), and that same pattern is used elsewhere in Avalonia libs, but for the record anyway

@Numpsy
Copy link
Collaborator Author

Numpsy commented Nov 5, 2023

Hey @Numpsy 👋

Looks like the DynamicMemberAccess attribute was completely missing for components.

b0aa279

Actually, only just noticed, but the error in the callstack is

No parameterless constructor defined for type 'Avalonia.FuncUI.Component'

but it appears that in fact, Component doesn't have a parameterless constructor anyway?

@JaggerJo
Copy link
Member

JaggerJo commented Nov 5, 2023

Yup, Component constructor needs a render function.

@Numpsy
Copy link
Collaborator Author

Numpsy commented Nov 5, 2023

But that makes it sound like something has gone awry and is trying to call the wrong constructor :-(
This is where C# having a source based analyzer for this stuff where F# has to rely in the IL level one becomes a pain

@JaggerJo
Copy link
Member

JaggerJo commented Nov 5, 2023

Yeah.. that should never happen. If you can reproduce it let me know and I'll take a look

@Numpsy
Copy link
Collaborator Author

Numpsy commented Nov 5, 2023

Something else must be getting removed when it shouldn't be I suppose.

fwiw, the two warnings about patcher.create go away if ViewDelta is annotated:

    type ViewDelta =
        { [<DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)>] ViewType: Type
          Attrs: AttrDelta list
          ConstructorArgs: obj array
          KeyDidChange: bool
          Outlet: (AvaloniaObject -> unit) voption }

but you then get

5>Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.ViewDelta(Type,FSharpList`1<Delta.AttrDelta>,Object[],Boolean,FSharpValueOption`1<FSharpFunc`2<AvaloniaObject,Unit>>): value stored in field 'Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.ViewType@' does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' requirements. The parameter 'viewType' of method 'Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.ViewDelta(Type,FSharpList`1<Delta.AttrDelta>,Object[],Boolean,FSharpValueOption`1<FSharpFunc`2<AvaloniaObject,Unit>>)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

from ViewDelta.From because IView isn't annoted, so it spirals off a bit into other things.

@Numpsy
Copy link
Collaborator Author

Numpsy commented Nov 5, 2023

Yeah.. that should never happen. If you can reproduce it let me know and I'll take a look

I get a similar error with the ContactBook sample project -

  1. Target the project to .NET 8
  2. Add <PublishAot>true</PublishAot> to the project file
  3. publish the project as a self contained executable

and it crashes when run.
It seems ok when building a single file / trimmed exe without AOT, and for comparison the counter test app seems fine as AOT so the base idea seems to work

@Numpsy
Copy link
Collaborator Author

Numpsy commented Mar 8, 2024

The change in #399 appears to fix the crash I was seeing before in a NativeAOT build on my app, and also gets the ContactBook example further (it then falls over inside Bogus, but that's a different situation)

@Numpsy
Copy link
Collaborator Author

Numpsy commented May 9, 2024

With the changes in #423 I have the control catalog running in NativeAOT in .NET 8.0 :-)

It does look like the drag and drop demo doesn't actually drag (on Windows at least), but that might be an issue with COM interop in Avalonia - needs an extra testing.
Looking much better than it was before though :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants