Skip to content

Fix attributes silently dropped on unparenthesized tuple return types#19714

Open
edgarfgp wants to merge 5 commits into
dotnet:mainfrom
edgarfgp:fix-462-v2
Open

Fix attributes silently dropped on unparenthesized tuple return types#19714
edgarfgp wants to merge 5 commits into
dotnet:mainfrom
edgarfgp:fix-462-v2

Conversation

@edgarfgp
Copy link
Copy Markdown
Contributor

Fixes #462

Problem

When a method return type is an unparenthesized tuple, any attributes placed before it are silently dropped and never emitted to IL:

// Attributes are DROPPED — bug
static member Format name :
    [<ReturnDescription("...")>]
    string * string = ...

// Attributes are KEPT — works
static member Format name :
    [<ReturnDescription("...")>]
    (string * string) = ...

Root cause

In pars.fsy, the topType → topTupleType grammar rule handles the return type annotation. When the return type is a bare multi-element tuple, rmdata (the list of SynArgInfo per tuple element) has more than one entry, so the rule fell into a catch-all branch that replaced everything with SynInfo.unnamedRetVal — an empty SynArgInfo with no attributes:

// Before
ty, (SynValInfo([], (match rmdata with [md] -> md | _ -> SynInfo.unnamedRetVal)))

The attributes were parsed correctly into the first element's SynArgInfo but then discarded here, never reaching SynBindingReturnInfo or IL emission.

Fix

Promote attributes from the first element's SynArgInfo to the overall return SynArgInfo when they are non-empty, since attributes placed before the whole tuple belong to the return position:

// After
let retArgInfo =
    match rmdata with
    | [md] -> md
    | SynArgInfo(attrs, _, _) :: _ when not attrs.IsEmpty -> SynArgInfo(attrs, false, None)
    | _ -> SynInfo.unnamedRetVal
ty, SynValInfo([], retArgInfo)

Tests

  • ReturnType04.fs — runtime reflection test asserting attributes appear on the return parameter for both parenthesized and bare tuple forms
  • Attribute/ReturnTypeAttributeOnBareTuple.fs + .bsl — SyntaxTree parser test documenting that SynValInfo now carries the correct SynArgInfo with attributes in the return position for bare tuples

edgarfgp and others added 2 commits May 11, 2026 14:05
…dotnet#462)

In `pars.fsy`, the `topType → topTupleType` rule discarded all `SynArgInfo`
entries via `SynInfo.unnamedRetVal` whenever the return type was a bare
multi-element tuple (e.g. `string * string`). Attributes placed before the
tuple were parsed into the first element's `SynArgInfo` but then silently
dropped, never reaching `SynBindingReturnInfo` or IL emission.

The fix promotes attributes from the first element's `SynArgInfo` to the
overall return `SynArgInfo` when they are non-empty, so that:

    static member Foo() :
        [<ReturnDescription("...")>]
        string * string = ...

now correctly emits the attribute to `.param [0]` in IL, matching the
behaviour of the parenthesized form `(string * string)`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These were side effects of running TEST_UPDATE_BSL=1 and are unrelated
to the fix for dotnet#462.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

Comment thread tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

No diagnostic when custom attributes ignored on unparenthesized tuple type

2 participants