Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions src/ProvidedTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7999,25 +7999,35 @@ namespace ProviderImplementation.ProvidedTypes
let propDefs = lazy (inp.Properties.Entries |> Array.map (txILPropertyDef this))
let nestedDefs = lazy (inp.NestedTypes.Entries |> Array.map (asm.TxILTypeDef (Some (this :> Type))))

// Cache derived properties that are computed from immutable input data.
// The F# compiler may call FullName, BaseType and GetInterfaces() many times per type
// during type-checking; caching avoids repeated string allocations and type-resolution work.
let fullName =
lazy (
match declTyOpt with
| None ->
match inp.Namespace with
| UNone -> inp.Name
| USome nsp -> nsp + "." + inp.Name
| Some declTy ->
declTy.FullName + "+" + inp.Name)

let baseType = lazy (inp.Extends |> Option.map (txILType (gps, [| |])) |> Option.toObj)

let interfaces = lazy (inp.Implements |> Array.map (txILType (gps, [| |])))

do this.typeImpl <- this
override __.Name = inp.Name
override __.Assembly = (asm :> Assembly)
override __.DeclaringType = declTyOpt |> Option.toObj
override __.MemberType = if isNested then MemberTypes.NestedType else MemberTypes.TypeInfo
override __.MetadataToken = inp.Token

override __.FullName =
match declTyOpt with
| None ->
match inp.Namespace with
| UNone -> inp.Name
| USome nsp -> nsp + "." + inp.Name
| Some declTy ->
declTy.FullName + "+" + inp.Name
override __.FullName = fullName.Value

override __.Namespace = inp.Namespace |> StructOption.toObj
override __.BaseType = inp.Extends |> Option.map (txILType (gps, [| |])) |> Option.toObj
override __.GetInterfaces() = inp.Implements |> Array.map (txILType (gps, [| |]))
override __.BaseType = baseType.Value
override __.GetInterfaces() = interfaces.Value
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetInterfaces() now returns the cached Type[] instance. Previously it allocated a fresh array on each call, so callers could (intentionally or accidentally) mutate the returned array without affecting subsequent calls. To avoid sharing a mutable array across callers, consider returning a copy (while still caching the resolved interface Types) or otherwise ensuring the returned collection can't be mutated by consumers.

Suggested change
override __.GetInterfaces() = interfaces.Value
override __.GetInterfaces() = interfaces.Value |> Array.copy

Copilot uses AI. Check for mistakes.

override __.GetConstructors(bindingFlags) =
ctorDefs.Force() |> Array.filter (canBindConstructor bindingFlags)
Expand Down
Loading