MethodImpl attribute is silently dropped on property accessors (and leaks into metadata as a real custom attribute)
- 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
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