dotnet / dotnet/fsharp

MethodImpl attribute is silently dropped on property accessors (and leaks into metadata as a real custom attribute)

Open
#20,288 0 comments 0 reactions 0 assignees View on GitHub
Area-Compiler-CodeGen Bug Needs-Triage
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

When `[]` is applied to a property accessor, the compiler does not translate it into the method's IL implementation flags. Instead it emits it as an ordinary custom attribute, which has no effect on the runtime or on downstream tools.

`MethodImplAttribute` is a pseudo-custom-attribute: it must be encoded in the method's `implflags`, and it should never appear in metadata as a real custom attribute.

The failure is silent. The code compiles without a warning, and the attribute looks like it was applied.

## Repro

```fsharp
module P
open System.Runtime.CompilerServices

[]
type A =
static member P1 with [] get () = 1

[]
type B =
static member P2 with [] set (v: int) = ignore v

[]
type C =
[]
static member M1() = 1
```

## Actual

Inspecting the emitted assembly:

```
A get_P1 implFlags=IL customAttrs=["MethodImplAttribute"]
B set_P2 implFlags=IL customAttrs=["MethodImplAttribute"]
C M1 implFlags=AggressiveInlining customAttrs=[]
```

The accessors `get_P1` and `set_P2` keep `implFlags=IL`, so the requested option is lost, and `MethodImplAttribute` is emitted as a custom attribute. The plain method `C.M1` is correct.

## Expected

`get_P1` and `set_P2` behave like `C.M1`: the option appears in `implflags` and no `MethodImplAttribute` custom attribute is emitted.

## Notes

This is not specific to `NoInlining`. It applies to any `MethodImplOptions` carried by an accessor, including `AggressiveInlining`, `Synchronized` and `PreserveSig`, and it affects both getters and setters.

The cause looks like `ComputeMethodImplAttribs` running on an attribute list that has already had the accessor-applied attributes partitioned out, in `IlxGen.fs` (around the `attrsAppliedToGetterOrSetter` handling).

`[]` on a property member (rather than inside the accessor) is not a workaround either, since that is rejected with `error FS0842: This attribute cannot be applied to property, event, return value. Valid targets are: constructor, method`. So a plain method is currently the only reliable way to request a method impl option.

## Why it matters

This was found while making `Array2D` trim- and AOT-clean. A trimming feature switch needs `MethodImplOptions.NoInlining` so that ILLink and ILC still have a real call to substitute. Written as a property getter (the shape every BCL feature switch uses, such as `RuntimeFeature.IsDynamicCodeSupported`), the attribute silently disappeared, and the only reason the substitution still worked was an unrelated compiler internal. There is no way to assert the intended contract from the emitted metadata, because the flag is simply not there.

Contributor guide

Open the contributing guide

Research direction

Start in IlxGen.fs around attrsAppliedToGetterOrSetter and trace how ComputeMethodImplAttribs receives accessor attributes. Use the F# repro to inspect emitted method implflags and custom attributes for getters and setters. Done means accessor MethodImplOptions are encoded in implflags, with no MethodImplAttribute custom attribute, matching the plain method case.

Written by the indexing model from the issue text.

Assessment

Tech stack
fsharp
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.