Skip to content

Can't build for release due to modreq from in #12656

Open

Description

@hamarb123

Android framework version

net10.0-android

Affected platform version

.NET 10.0.400 SDK

Description

The build fails, due to not handling all edge cases here: https://github.com/dotnet/android/blob/main/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs#L84-L105.

Might be worth also handling any other similar cases, like IsSentinel, IsOptionalModifier, IsRequiredModifier, IsFunctionPointer, IsPointer (there may be others too). I can also repro with pointers, and haven't tried any others.

Steps to Reproduce

I used AI to help me get this relatively minimal repro.

  • Run dotnet new android -n Proj1
  • Run dotnet new androidlib -n Proj2
  • Add reference to Proj2 from Proj1
  • Add this code to MainActivity.cs:
        var renderer = new ConcreteRenderer();
        var context = new Context();
        renderer.Render(in context);
  • Edit Class1.cs in Proj2 to:
#nullable disable

namespace ReproLibrary;

public struct Context
{
    public int Value;
}

public interface IRenderer
{
    void Render(in Context context);
}

public abstract class Renderer : Java.Lang.Object, IRenderer
{
    public abstract void Render(in Context context);
}

public sealed class ConcreteRenderer : Renderer, IRenderer
{
    public override void Render(in Context context)
    {
    }
}
  • Build with dotnet build -c Debug (succeeds)
  • Build with dotnet build -c Release (fails)
  • If you build with -v diag you will see the error:
16:50:18.052   1:9>ILLink : error IL1012: IL Trimmer has encountered an unexpected error. Please report the issue at https://aka.ms/report-illink [C:\Users\Hamish\Projects\Tests\TestAndroidInMethod\Proj1\Proj1.csproj]
                     Fatal error in IL Linker (TaskId:81)
                     Unhandled exception. System.NotSupportedException: TypeDefinition cannot be resolved from 'Mono.Cecil.RequiredModifierType' type (TaskId:81)
                        at Mono.Linker.LinkContext.Resolve(TypeReference typeReference) (TaskId:81)
                        at MonoDroid.Tuner.FixAbstractMethodsStep.CompareTypes(TypeReference iType, TypeReference tType) (TaskId:81)
                        at MonoDroid.Tuner.FixAbstractMethodsStep.HaveSameSignature(TypeReference iface, MethodDefinition iMethod, MethodDefinition tMethod) (TaskId:81)
                        at MonoDroid.Tuner.FixAbstractMethodsStep.FixAbstractMethods(TypeDefinition type) (TaskId:81)
                        at MonoDroid.Tuner.FixAbstractMethodsStep.ProcessType(TypeDefinition type) (TaskId:81)
                        at MonoDroid.Tuner.FixAbstractMethodsStep.<Initialize>b__0_0(TypeDefinition type) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.MarkType(TypeReference reference, DependencyInfo reason, MessageOrigin origin) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference, DependencyInfo reason, MessageOrigin& origin) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction, MethodDefinition method, Boolean& requiresReflectionMethodBodyScanner, MessageOrigin& origin) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.MarkAndCheckRequiresReflectionMethodBodyScanner(MethodIL methodIL, MessageOrigin origin) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body, MessageOrigin origin) (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.ProcessPendingBodies() (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue() (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.Process() (TaskId:81)
                        at Mono.Linker.Steps.MarkStep.Process(LinkContext context) (TaskId:81)
                        at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step) (TaskId:81)
                        at Mono.Linker.Pipeline.Process(LinkContext context) (TaskId:81)
                        at Mono.Linker.Driver.Run(ILogger customLogger) (TaskId:81)
                        at Mono.Linker.Driver.Main(String[] args) (TaskId:81)

Did you find any workaround?

Don't use in or ref readonly, pointers, etc., in any types that inherit from Object outside of the main app project.

Relevant log output

Additional Info

It also repros with

#nullable disable

namespace ReproLibrary;

public struct Context
{
    public int Value;
}

public interface IRenderer
{
    void Render(in Context context);
}

public class ConcreteRenderer : Java.Lang.Object, IRenderer
{
    public virtual void Render(in Context context)
    {
    }
}

I think, which is closer to my original setup.

Activity

  1. added
    Area: App+Library BuildIssues when building Library projects or Application projects.
    needs-triageIssues that need to be assigned.
    on Sep 3, 2026
  2. jonathanpeppers commented on Sep 3, 2026

    @jonathanpeppers
    Member

    FixAbstractMethodsStep is more about fixing interfaces that change across Android API levels. This happened to ICursor at one point many years ago.

    You don't mention changing the API level between Proj1 and Proj2, is there something missing in the repro? Or is the file you linked to incorrect?

    Ideally, if you could share that sample project that would be best, thanks!

  3. added
    need-infoIssues that need more information from the author.
    and removed
    needs-triageIssues that need to be assigned.
    on Sep 3, 2026
  4. dotnet-policy-service commented on Sep 3, 2026

    @dotnet-policy-service

    Hi @hamarb123. We have added the "need-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

  5. hamarb123 commented on Sep 3, 2026

    @hamarb123
    Author

    FixAbstractMethodsStep is more about fixing interfaces that change across Android API levels. This happened to ICursor at one point many years ago.

    You don't mention changing the API level between Proj1 and Proj2, is there something missing in the repro? Or is the file you linked to incorrect?

    Ideally, if you could share that sample project that would be best, thanks!

    No, I don't change anything - the step crashes as it doesn't handle the type system properly is the cause afaict (it assumes that the only non-TypeRef/Def/Spec types are generic parameters, arrays, byrefs, and misses other cases like pointers, modreqs, modopts, function pointers, etc., which all crash for TypeCache.Resolve). Here's the repro in a zip:

    TestAndroidInMethod.zip (do dotnet build -c Release in Proj1 to repro)

    Afaik the interface doesn't have to be in the android project either - in my real solution, the interface is in a different project that just targets net10.0, the issue is just that I implement it on a type that inherits from Java.Lang.Object, and then this task throws an exception due to missing handling (of in this case modreq - it also repro's if you put in pointer for example).

  6. added
    need-attentionA xamarin-android contributor needs to review
    and removed
    need-infoIssues that need more information from the author.
    on Sep 3, 2026
  7. jonathanpeppers commented on Sep 3, 2026

    @jonathanpeppers
    Member

    This appears to already be fixing in main/.NET 11. There is refactoring related to trimming that I believe fixed this.

    If you get the latest .NET 11 release, is it solved for you there?

  8. hamarb123 commented on Sep 3, 2026

    @hamarb123
    Author

    @jonathanpeppers it does appear to be fixed in .NET 11 SDK when targeting .NET 11, it doesn't fix with .NET 11 SDK targeting .NET 10. It would be nice if it could be fixed for .NET 10 also, in my case, the only problematic one I have in my code is the modreq one for in.

    Thanks for letting me know that it will be fixed in the future on its own though :)

  9. jonathanpeppers commented on Sep 4, 2026

    @jonathanpeppers
    Member

    Unfortunately, it is not a small change that fixed it -- so we can't easily backport to 10.

    .NET 11 RC 1 is coming soon, if they mark it production/"go live" would that be good enough?

  10. hamarb123 commented on Sep 4, 2026

    @hamarb123
    Author

    Unfortunately, it is not a small change that fixed it

    A different fix could easily be implemented for .NET 10, where it just maps modreq to the element type & compares that. Would that not work?

    If not, then I can wait for .NET 11, but I would have thought it'd be relatively to fix it for .NET 10 also.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App+Library BuildIssues when building Library projects or Application projects.need-attentionA xamarin-android contributor needs to review

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions