Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rust] Improved member lookup #3909

Merged
merged 1 commit into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
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
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
Loading