Skip to content

Commit

Permalink
[Rust] Improved member lookup (#3909)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave authored Sep 30, 2024
1 parent f2cd06f commit dcf1c67
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 69 deletions.
6 changes: 4 additions & 2 deletions src/Fable.Transforms/FSharp2Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,7 @@ module TypeHelpers =
(com: IFableCompiler)
(ent: FSharpEntity)
(compiledName: string)
(isInstance: bool)
(argTypes: Fable.Type[] option)
=
let entRef = FsEnt.Ref ent
Expand All @@ -1653,7 +1654,7 @@ module TypeHelpers =
|> Option.bind (fun ent ->
match ent with
| :? FsEnt as entity ->
entity.TryFindMember(compiledName, isInstance = true, ?argTypes = argTypes, requireDispatchSlot = true)
entity.TryFindMember(compiledName, isInstance, ?argTypes = argTypes, requireDispatchSlot = true)
| _ -> None
)

Expand Down Expand Up @@ -2799,7 +2800,8 @@ module Util =

entity
|> tryFindBaseEntity (fun ent ->
tryFindAbstractMember com ent memb.CompiledName paramTypes |> Option.isSome
tryFindAbstractMember com ent memb.CompiledName memb.IsInstanceMember paramTypes
|> Option.isSome
)
|> Option.defaultValue entity
| _ -> entity
Expand Down
6 changes: 4 additions & 2 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ let private getImplementedSignatureInfo
nonMangledNameConflicts
(implementingEntity: FSharpEntity option)
(sign: FSharpAbstractSignature)
isInstance
=
let implementingEntityFields = HashSet<_>()

Expand All @@ -347,7 +348,7 @@ let private getImplementedSignatureInfo
else
None

tryFindAbstractMember com ent sign.Name paramTypes
tryFindAbstractMember com ent sign.Name isInstance paramTypes
|> Option.map (fun m -> ent, m)
)
|> Option.map (fun (ent, memb) ->
Expand Down Expand Up @@ -424,7 +425,7 @@ let private transformObjExpr
let r = makeRangeFrom over.Body

let info =
getImplementedSignatureInfo com ctx r nonMangledNameConflicts None signature
getImplementedSignatureInfo com ctx r nonMangledNameConflicts None signature true

let ctx, args = bindMemberArgs com ctx over.CurriedParameterGroups
let! body = transformExpr com ctx [] over.Body
Expand Down Expand Up @@ -1832,6 +1833,7 @@ let private transformImplementedSignature
com.NonMangledAttachedMemberConflicts
(Some implementingEntity)
signature
memb.IsInstanceMember

com.AddAttachedMember(
entFullName,
Expand Down
132 changes: 67 additions & 65 deletions src/Fable.Transforms/Rust/Fable2Rust.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2043,6 +2043,24 @@ module Util =
// | None, _ ->
// None

let getDeclMember (com: IRustCompiler) (decl: Fable.MemberDecl) =
decl.ImplementedSignatureRef
|> Option.defaultValue decl.MemberRef
|> com.GetMember

let getDistinctInterfaceMembers (com: IRustCompiler) (ent: Fable.Entity) =
assert (ent.IsInterface)

FSharp2Fable.Util.getInterfaceMembers com ent
|> Seq.filter (fun (ifc, memb) -> not memb.IsProperty)
|> Seq.distinctBy (fun (ifc, memb) -> memb.CompiledName) // skip inherited overwrites

let getInterfaceMemberNames (com: IRustCompiler) (entRef: Fable.EntityRef) =
let ent = com.GetEntity(entRef)

getDistinctInterfaceMembers com ent
|> Seq.map (fun (ifc, memb) -> memb.FullName)
|> Set.ofSeq

let makeObjectExprMemberDecl (com: IRustCompiler) ctx (memb: Fable.ObjectExprMember) =
let capturedIdents = getCapturedIdents com ctx (Some memb.Name) memb.Args memb.Body
Expand Down Expand Up @@ -2141,11 +2159,12 @@ module Util =

let ctx = { ctx with ScopedEntityGenArgs = getEntityGenParamNames ent }

let memberNames = getInterfaceMemberNames com entRef

let memberItems =
members
|> List.map (fun decl -> decl, com.GetMember(decl.MemberRef))
|> List.filter (fun (d, m) -> isInterfaceMember com entRef m)
|> List.distinctBy (fun (d, m) -> Fable.Naming.splitLast m.CompiledName)
|> List.map (fun decl -> decl, getDeclMember com decl)
|> List.filter (fun (d, m) -> Set.contains m.FullName memberNames)
|> List.map (makeMemberItem com ctx false)
|> makeInterfaceTraitImpls com ctx entName genParams entRef genArgs

Expand Down Expand Up @@ -4058,25 +4077,6 @@ module Util =
let fnItem = mkFnAssocItem attrs name fnKind
fnItem

let isInterfaceMember (com: IRustCompiler) (entRef: Fable.EntityRef) (memb: Fable.MemberFunctionOrValue) =
let ent = com.GetEntity(entRef)
assert (ent.IsInterface)

match memb.DeclaringEntity with
| Some declEntRef ->
let declEnt = com.GetEntity(declEntRef)

if declEnt.IsInterface then
ent.AllInterfaces |> Seq.exists (fun ifc -> ifc.Entity = declEntRef)
else
// if declaring entity is not an interface, the interface is in the member.CompiledName
let ifcName, membName = Fable.Naming.splitLastBy "." memb.CompiledName
let ifcName, _ = Fable.Naming.splitFirstBy "<" ifcName // trim the generics

ent.AllInterfaces
|> Seq.exists (fun ifc -> ifc.Entity.FullName.StartsWith(ifcName))
| None -> false

let makeDerivedFrom com (ent: Fable.Entity) =
let isCopyable = ent |> isCopyableEntity com Set.empty
let isPrintable = ent |> isPrintableEntity com Set.empty
Expand Down Expand Up @@ -4272,12 +4272,7 @@ module Util =
fnItem

let makeInterfaceItems (com: IRustCompiler) ctx hasBody typeName (ent: Fable.Entity) =
assert (ent.IsInterface)

ent
|> FSharp2Fable.Util.getInterfaceMembers com
|> Seq.filter (fun (ifc, memb) -> memb.IsDispatchSlot) // TODO: is that needed?
|> Seq.distinctBy (fun (ifc, memb) -> Fable.Naming.splitLast memb.CompiledName) // skip inherited overwrites
getDistinctInterfaceMembers com ent
|> Seq.map (fun (ifc, memb) ->
let ifcEnt = com.GetEntity(ifc.Entity)
let ifcTyp = Fable.DeclaredType(ifc.Entity, ifc.GenericArgs)
Expand Down Expand Up @@ -4536,16 +4531,16 @@ module Util =
let implItem = mkImplItem [] "" ty generics memberItems ofTrait
[ implItem ]

let objectMemberNames =
set
[
"Equals"
"GetHashCode"
"GetType"
"ToString"
// "MemberwiseClone"
// "ReferenceEquals"
]
// let objectMemberNames =
// set
// [
// // "Equals"
// // "GetHashCode"
// // "MemberwiseClone"
// // "ReferenceEquals"
// "GetType"
// "ToString"
// ]

let ignoredInterfaceNames = set [ Types.ienumerable; Types.ienumerator ]

Expand Down Expand Up @@ -4576,17 +4571,21 @@ module Util =
let ctx = { ctx with ScopedEntityGenArgs = getEntityGenParamNames ent }

// to filter out compiler-generated exception equality
let isNotExceptionMember (_m: Fable.MemberFunctionOrValue) = not (ent.IsFSharpExceptionDeclaration)

let isNonInterfaceMember (m: Fable.MemberFunctionOrValue) =
m.IsConstructor
|| (not ent.IsInterface && not m.IsOverrideOrExplicitInterfaceImplementation)
|| (not ent.IsInterface && Set.contains m.CompiledName objectMemberNames)

let nonInterfaceMembers, interfaceMembers =
let isNotExceptionMember (_memb: Fable.MemberFunctionOrValue) = not (ent.IsFSharpExceptionDeclaration)

let isInterfaceMember (memb: Fable.MemberFunctionOrValue) =
memb.IsDispatchSlot
&& (memb.DeclaringEntity
|> Option.bind com.TryGetEntity
|> Option.map (fun ent -> ent.IsInterface)
|> Option.defaultValue false)
// || memb.IsOverrideOrExplicitInterfaceImplementation)
// && not (Set.contains memb.CompiledName objectMemberNames)

let interfaceMembers, nonInterfaceMembers =
classDecl.AttachedMembers
|> List.map (fun decl -> decl, com.GetMember(decl.MemberRef))
|> List.partition (snd >> isNonInterfaceMember)
|> List.map (fun decl -> decl, getDeclMember com decl)
|> List.partition (snd >> isInterfaceMember)

let nonInterfaceImpls =
let memberItems =
Expand All @@ -4603,34 +4602,37 @@ module Util =
let implItem = mkImplItem [] "" self_ty generics memberItems None
[ implItem ]

let nonInterfaceMemberNames =
nonInterfaceMembers |> List.map (fun (d, m) -> d.Name) |> Set.ofList

let displayTraitImpls =
if ent.IsInterface then
[]
else
let hasToString = Set.contains "ToString" nonInterfaceMemberNames
let hasToString =
nonInterfaceMembers |> List.exists (fun (d, m) -> m.CompiledName = "ToString")

makeDisplayTraitImpls com ctx self_ty genArgs hasToString

let operatorTraitImpls =
nonInterfaceMembers
|> List.choose (makeOpTraitImpls com ctx ent entType self_ty genArgTys)

let interfaceTraitImpls =
getAllInterfaces ent
|> List.collect (fun ifc ->
let memberItems =
interfaceMembers
|> List.filter (fun (d, m) -> isInterfaceMember com ifc.Entity m)
|> List.distinctBy (fun (d, m) -> Fable.Naming.splitLast m.CompiledName)
|> List.map (makeMemberItem com ctx false)

if List.isEmpty memberItems then
[]
else
makeInterfaceTraitImpls com ctx entName genArgs ifc.Entity ifc.GenericArgs memberItems
)
if List.isEmpty interfaceMembers then
[]
else
getAllInterfaces ent
|> List.collect (fun ifc ->
let memberNames = getInterfaceMemberNames com ifc.Entity

let memberItems =
interfaceMembers
|> List.filter (fun (d, m) -> Set.contains m.FullName memberNames)
|> List.map (makeMemberItem com ctx false)

if List.isEmpty memberItems then
[]
else
makeInterfaceTraitImpls com ctx entName genArgs ifc.Entity ifc.GenericArgs memberItems
)

nonInterfaceImpls @ displayTraitImpls @ operatorTraitImpls @ interfaceTraitImpls

Expand Down

0 comments on commit dcf1c67

Please sign in to comment.