Skip to content

[Repo Assist] Fix generative delegate type support; implement GetInterface on ProvidedTypeDefinition#479

Draft
github-actions[bot] wants to merge 4 commits intomasterfrom
repo-assist/fix-generative-delegate-types-20260319-143b419654defae8
Draft

[Repo Assist] Fix generative delegate type support; implement GetInterface on ProvidedTypeDefinition#479
github-actions[bot] wants to merge 4 commits intomasterfrom
repo-assist/fix-generative-delegate-types-20260319-143b419654defae8

Conversation

@github-actions
Copy link
Contributor

🤖 This is an automated PR from Repo Assist, an AI assistant for this repository.

Summary

Two related fixes for correctness gaps in the SDK.


Bug fix: Generative delegate types were unsupported (Task 3)

Attempting to create a generative ProvidedTypeDefinition that extends System.MulticastDelegate would previously fail at assembly-writing time with:

"The provided method is not marked as an abstract method; therefore, it should define an implementation."

The root cause: .NET delegate types are special. Their .ctor(object, nativeint) and Invoke/BeginInvoke/EndInvoke methods must carry MethodImplAttributes.Runtime | MethodImplAttributes.Managed — the CLR synthesises their bodies at JIT time, and no IL body is ever written in the binary. The old assembly writer had no path for this case.

Changes in ProvidedTypes.fs:

  • Add ILMethodBuilder.SetImplementationFlags to expose impl-attribute control
  • In assembly writer phase 2, detect delegate types (BaseType.FullName = "System.MulticastDelegate") and set Runtime|Managed impl flags on all their constructors and methods
  • In assembly writer phase 3, skip IL body emission for delegate type constructors and methods (the CLR synthesises them)

Example usage that now works:

let myHandler = ProvidedTypeDefinition("MyHandler", Some typeof(System.MulticastDelegate), isErased = false)
myHandler.AddMember(
    ProvidedConstructor(
        [ ProvidedParameter("object", typeof(obj))
          ProvidedParameter("method", typeof(nativeint)) ],
        invokeCode = fun _ -> <@@ () @@>))          // invokeCode is ignored for delegate types
myHandler.AddMember(
    ProvidedMethod("Invoke",
        [ ProvidedParameter("sender", typeof(obj))
          ProvidedParameter("e", typeof(EventArgs)) ],
        typeof(Void)))
```

---

### Coding improvement: `GetInterface` now works instead of throwing (Task 5)

`ProvidedTypeDefinition.GetInterface(name, ignoreCase)` and `TargetTypeDefinition.GetInterface(name, ignoreCase)` previously threw `NotSupportedException`. They now search through `GetInterfaces()`, matching on `Name` (short name) or `FullName` (dotted name), consistent with how `TypeDelegator` implements this in .NET.

---

### Tests

Added `tests/GenerativeDelegateTests.fs` with **5 new tests**:

| Test | What it verifies |
|------|-----------------|
| `Generative delegate type is present in generated assembly` | Type exists with `MulticastDelegate` as base |
| `Generative delegate type has correct constructor` | `.ctor(object, nativeint)` present with correct param types |
| `Generative delegate Invoke method has correct signature` | `Invoke(object, EventArgs): void` |
| `Generative delegate with value return type has correct Invoke signature` | `Invoke(int, int): int` |
| `Multiple delegate types can coexist in one container` | Both delegate types present; both have `MulticastDelegate` base |

## Test Status

All **122 tests pass** (117 pre-existing + 5 new), `net8.0`.

```
Passed!  - Failed: 0, Passed: 122, Skipped: 0, Total: 122

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f

…dedTypeDefinition

Task 3 (bug fix): Support generative delegate types in the assembly writer.
Previously, attempting to create a ProvidedTypeDefinition that extends
System.MulticastDelegate would fail because the assembly writer required
all methods to either have an invokeCode or be abstract/interface members.

Delegate types are special: their .ctor(object, nativeint) and Invoke/
BeginInvoke/EndInvoke methods must carry MethodImplAttributes.Runtime so the
CLR synthesises their bodies. No IL body is ever emitted for these methods.

Changes in ProvidedTypes.fs:
- Add ILMethodBuilder.SetImplementationFlags to allow setting impl attributes
- In assembly writer phase 2, detect delegate types and set Runtime|Managed
  impl flags on all their constructors and methods
- In assembly writer phase 3, skip IL body emission for delegate type
  constructors and methods (the CLR synthesises them from the impl flags)
- Fix ProvidedTypeDefinition.GetInterface(name, ignoreCase) to search through
  GetInterfaces() instead of throwing NotSupportedException
- Fix TargetTypeDefinition.GetInterface(name, ignoreCase) similarly

Task 5 (coding improvement): Add GenerativeDelegateTests.fs with 5 tests that
verify generative delegate type generation produces correct type structure
(correct base type, constructor signatures, Invoke signatures).

122 tests pass (117 pre-existing + 5 new).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dsyme
Copy link
Contributor

dsyme commented Mar 19, 2026

/repo-assist Fix these CI errors please

/home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK> /usr/share/dotnet/dotnet build src/FSharp.TypeProviders.SDK.fsproj --configuration Release /nodeReuse:False /clp:ForceConsoleColor (In: false, Out: false, Err: false)
MSBuild version 17.8.49+7806cbf7b for .NET
Determining projects to restore...
Restored /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/FSharp.TypeProviders.SDK.fsproj (in 808 ms).
Error: /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/ProvidedTypes.fs(1664,30): error FS0001: This expression was expected to have type� 'string' �but here has type� 'char' [/home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/FSharp.TypeProviders.SDK.fsproj::TargetFramework=netstandard2.0]
Error: /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/ProvidedTypes.fs(8161,34): error FS0001: This expression was expected to have type� 'string' �but here has type� 'char' [/home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/FSharp.TypeProviders.SDK.fsproj::TargetFramework=netstandard2.0]
FSharp.TypeProviders.SDK -> /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/bin/Release/net8.0/FSharp.TypeProviders.SDK.dll

Build FAILED.

Error: /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/ProvidedTypes.fs(1664,30): error FS0001: This expression was expected to have type� 'string' �but here has type� 'char' [/home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/FSharp.TypeProviders.SDK.fsproj::TargetFramework=netstandard2.0]
Error: /home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/ProvidedTypes.fs(8161,34): error FS0001: This expression was expected to have type� 'string' �but here has type� 'char' [/home/runner/work/FSharp.TypeProviders.SDK/FSharp.TypeProviders.SDK/src/FSharp.TypeProviders.SDK.fsproj::TargetFramework=netstandard2.0]
0 Warning(s)
2 Error(s)

Replace char literal '.' with string literal "." in String.Contains calls
at lines 1664 and 8161, as the char overload is not available in netstandard2.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Contributor Author

Commit pushed: b1d5c7f

Generated by Repo Assist

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant