Commit 6c8ab20
[Repo Assist] perf: avoid O(n²) allocations in ILMethodDefs; use lazy caches in TargetTypeDefinition member lookups (#497)
🤖 *This is an automated PR from Repo Assist.*
## Summary
Two complementary performance improvements to `TargetTypeDefinition` and
the internal `ILMethodDefs` name-index.
### 1. O(1)-per-entry method-name index construction
(`ILMethodDefs.lmap`)
**Before**: the lazy name→methods dictionary was built by prepending
each new entry to an existing array:
```fsharp
m.[key] <- Array.append [| y |] lmpak // O(n) per insertion
```
For a type with N methods sharing a name, this allocates arrays of sizes
1, 2, 3 … N — **O(N²) total elements**. The BCL contains types (e.g.
`String`, `Convert`) with dozens of overloads per name, making this
measurable.
**After**: a `ResizeArray` accumulator collects entries per name in O(1)
each, then a single `ToArray()` call per bucket produces the final
arrays — **O(N) total elements**.
### 2. Lazy-cache reuse in `GetField`, `GetPropertyImpl`, `GetEvent`
**Before**: each call to `GetField`/`GetPropertyImpl`/`GetEvent` scanned
the raw `ILFieldDef`/`ILPropertyDef`/`ILEventDef` arrays and called the
`txIL*` factory to create a brand-new wrapper object:
```fsharp
inp.Fields.Entries |> Array.tryPick (fun p -> if p.Name = name then Some (txILFieldDef this p) else None)
```
This created a **new allocation on every call** even when
`fieldDefs`/`propDefs`/`eventDefs` lazy arrays were already fully
computed (e.g. after a preceding `GetFields(bindingFlags)` call).
**After**: the methods call `Force()` on the already-computed lazy
arrays and filter by name. When the caches are warm (the common case
during compilation) **zero new wrappers are allocated**, and callers get
consistent object identity across `GetFields`/`GetField` pairs.
## Test Status
✅ 126/126 tests pass (`dotnet test
tests/FSharp.TypeProviders.SDK.Tests.fsproj`).
> Generated by 🌈 Repo Assist, see [workflow
run](https://github.com/fsprojects/FSharp.TypeProviders.SDK/actions/runs/23928413736).
[Learn
more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).
>
> To install this [agentic
workflow](https://github.com/githubnext/agentics/blob/e1ecf341a90b7bc2021e77c58685d7e269e20b99/workflows/repo-assist.md),
run
> ```
> gh aw add
githubnext/agentics@e1ecf34
> ```
<!-- gh-aw-agentic-workflow: Repo Assist, engine: copilot, model: auto,
id: 23928413736, workflow_id: repo-assist, run:
https://github.com/fsprojects/FSharp.TypeProviders.SDK/actions/runs/23928413736
-->
<!-- gh-aw-workflow-id: repo-assist -->
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>1 parent 56473b1 commit 6c8ab20
1 file changed
+11
-13
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2881 | 2881 | | |
2882 | 2882 | | |
2883 | 2883 | | |
2884 | | - | |
| 2884 | + | |
| 2885 | + | |
| 2886 | + | |
2885 | 2887 | | |
2886 | 2888 | | |
2887 | | - | |
2888 | | - | |
2889 | | - | |
| 2889 | + | |
| 2890 | + | |
| 2891 | + | |
| 2892 | + | |
| 2893 | + | |
2890 | 2894 | | |
2891 | 2895 | | |
2892 | 2896 | | |
| |||
8058 | 8062 | | |
8059 | 8063 | | |
8060 | 8064 | | |
8061 | | - | |
8062 | | - | |
8063 | | - | |
| 8065 | + | |
8064 | 8066 | | |
8065 | 8067 | | |
8066 | | - | |
8067 | | - | |
8068 | | - | |
| 8068 | + | |
8069 | 8069 | | |
8070 | 8070 | | |
8071 | | - | |
8072 | | - | |
8073 | | - | |
| 8071 | + | |
8074 | 8072 | | |
8075 | 8073 | | |
8076 | 8074 | | |
| |||
0 commit comments