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] Updated derived interfaces #3951

Merged
merged 1 commit into from
Nov 8, 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
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,21 @@
"cwd": "${workspaceRoot}/../fable-test",
"stopAtEntry": false,
"console": "internalConsole"
},
{
"name": "Bench.Cli on ../fable-test",
"type": "coreclr",
"request": "launch",
"program": "${workspaceRoot}/src/fable-standalone/test/bench-compiler/src/bin/Debug/net8.0/bench-compiler.dll",
"args": [
"fable-test.fsproj",
"--outDir", "${workspaceRoot}/../fable-test",
"--fableLib", "${workspaceRoot}/temp/fable-library-rust",
"--lang", "Rust"
],
"cwd": "${workspaceRoot}/../fable-test",
"stopAtEntry": false,
"console": "internalConsole"
}
]
}
1 change: 1 addition & 0 deletions src/Fable.Cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

* [Rust] Updated derived interfaces (by @ncave)
* [Rust] Updated string comparisons (by @ncave)
* [Rust] Fixed derived traits mapping (by @ncave)
* [JS/TS] Added missing ICollection helpers (#3914) (by @ncave)
Expand Down
179 changes: 91 additions & 88 deletions src/Fable.Transforms/Rust/Fable2Rust.fs
Original file line number Diff line number Diff line change
Expand Up @@ -402,96 +402,95 @@ module TypeInfo =
ent.IsValueType
| _ -> false

let hasTypeOfType (com: IRustCompiler) isTypeOf isEntityOf entNames typ =
let isTypeOfType (com: IRustCompiler) isTypeOf isEntityOf entNames typ =
match typ with
| Fable.Option(genArg, _) -> isTypeOf com entNames genArg
| Fable.Array(genArg, _) -> isTypeOf com entNames genArg
| Fable.List genArg -> isTypeOf com entNames genArg
| Fable.Tuple(genArgs, _) -> List.exists (isTypeOf com entNames) genArgs
| Fable.AnonymousRecordType(_, genArgs, _) -> List.exists (isTypeOf com entNames) genArgs
| Fable.Tuple(genArgs, _) -> List.forall (isTypeOf com entNames) genArgs
| Fable.AnonymousRecordType(_, genArgs, _) -> List.forall (isTypeOf com entNames) genArgs
| Replacements.Util.Builtin(Replacements.Util.FSharpSet genArg) -> isTypeOf com entNames genArg
| Replacements.Util.Builtin(Replacements.Util.FSharpMap(k, v)) ->
isTypeOf com entNames k || isTypeOf com entNames v
isTypeOf com entNames k && isTypeOf com entNames v
| Fable.DeclaredType(entRef, _genArgs) ->
let ent = com.GetEntity(entRef)
isEntityOf com entNames ent //|| hasFieldOfType com isTypeOf entNames ent
| _ -> false
isEntityOf com entNames ent
| _ -> true

let hasFieldOfType (com: IRustCompiler) isTypeOf entNames (ent: Fable.Entity) =
let hasFieldsOfType (com: IRustCompiler) isTypeOf entNames (ent: Fable.Entity) =
if Set.contains ent.FullName entNames then
false // already checked, avoids circular checks
true // already checked, avoids circular checks
else
let entNames = Set.add ent.FullName entNames

if ent.IsFSharpUnion then
ent.UnionCases
|> Seq.exists (fun uci ->
|> Seq.forall (fun uci ->
uci.UnionCaseFields
|> List.exists (fun fi -> isTypeOf com entNames fi.FieldType)
|> List.forall (fun fi -> isTypeOf com entNames fi.FieldType)
)
else
ent.FSharpFields |> Seq.exists (fun fi -> isTypeOf com entNames fi.FieldType)
ent.FSharpFields |> Seq.forall (fun fi -> isTypeOf com entNames fi.FieldType)

let isNonPrintableType (com: IRustCompiler) entNames typ =
match typ with
// TODO: more unprintable types?
| _ -> hasTypeOfType com isNonPrintableType isNonPrintableEntity entNames typ
// let isPrintableType (com: IRustCompiler) entNames typ =
// match typ with
// // TODO: more unprintable types?
// | _ -> isTypeOfType com isPrintableType isPrintableEntity entNames typ

let isNonPrintableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface || (hasFieldOfType com isNonPrintableType entNames ent)
let isPrintableEntity com entNames (ent: Fable.Entity) = (List.isEmpty ent.GenericParameters)
// && (hasFieldsOfType com isPrintableType entNames ent) // commented as it kills performance

let isNonDefaultableType (com: IRustCompiler) entNames typ =
let isDefaultableType (com: IRustCompiler) entNames typ =
match typ with
// TODO: more undefaultable types?
| _ -> hasTypeOfType com isNonDefaultableType isNonDefaultableEntity entNames typ

let isNonDefaultableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface
|| not ent.IsValueType
|| ent.IsFSharpUnion // deriving 'Default' on enums is experimental
|| (hasFieldOfType com isNonDefaultableType entNames ent)

let isNonCopyableType (com: IRustCompiler) entNames typ =
match typ with
// TODO: more uncopyable types?
| Fable.Any
| Fable.Unit
| Fable.Measure _
| Fable.MetaType
| Fable.LambdaType _
| Fable.DelegateType _
| Fable.GenericParam _
| Fable.String
| Fable.Regex -> true
| Fable.Tuple(genArgs, isStruct) when not isStruct -> true
| Fable.AnonymousRecordType(_, genArgs, isStruct) when not isStruct -> true
| _ -> hasTypeOfType com isNonCopyableType isNonCopyableEntity entNames typ

let isNonCopyableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface
|| not ent.IsValueType
|| (hasMutableFields com ent)
|| (hasFieldOfType com isNonCopyableType entNames ent)

let isNonEquatableType (com: IRustCompiler) entNames typ =
| _ -> isTypeOfType com isDefaultableType isDefaultableEntity entNames typ

let isDefaultableEntity com entNames (ent: Fable.Entity) =
ent.IsValueType
&& not ent.IsFSharpUnion // default union cases are quite limited
&& (hasFieldsOfType com isDefaultableType entNames ent)

// let isCopyableType (com: IRustCompiler) entNames typ =
// match typ with
// // TODO: more uncopyable types?
// | Fable.Any
// | Fable.Unit
// | Fable.Measure _
// | Fable.MetaType
// | Fable.LambdaType _
// | Fable.DelegateType _
// | Fable.GenericParam _
// | Fable.String
// | Fable.Regex
// | Fable.List _ -> false
// | Fable.Option(_, isStruct) when not isStruct -> false
// | Fable.Tuple(_, isStruct) when not isStruct -> false
// | Fable.AnonymousRecordType(_, _, isStruct) when not isStruct -> false
// | _ -> isTypeOfType com isCopyableType isCopyableEntity entNames typ

// let isCopyableEntity com entNames (ent: Fable.Entity) =
// ent.IsValueType
// && not (hasMutableFields com ent)
// && (hasFieldsOfType com isCopyableType entNames ent)

let isEquatableType (com: IRustCompiler) entNames typ =
match typ with
// TODO: more unequatable types?
| Fable.Any
| Fable.Unit
| Fable.Measure _
| Fable.MetaType
| Fable.LambdaType _
| Fable.DelegateType _ -> true
| Fable.DelegateType _ -> false
// | Fable.GenericParam(_, _, constraints) ->
// not (constraints |> List.contains Fable.Constraint.HasEquality)
| _ -> hasTypeOfType com isNonEquatableType isNonEquatableEntity entNames typ
// constraints |> List.contains Fable.Constraint.HasEquality
| _ -> isTypeOfType com isEquatableType isEquatableEntity entNames typ

let isNonEquatableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface
|| not (FSharp2Fable.Util.hasStructuralEquality ent)
|| (hasFieldOfType com isNonEquatableType entNames ent)
let isEquatableEntity com entNames (ent: Fable.Entity) =
(FSharp2Fable.Util.hasStructuralEquality ent)
&& (hasFieldsOfType com isEquatableType entNames ent)

let isNonComparableType (com: IRustCompiler) entNames typ =
let isComparableType (com: IRustCompiler) entNames typ =
match typ with
// TODO: more uncomparable types?
| Fable.Any
Expand All @@ -500,17 +499,16 @@ module TypeInfo =
| Fable.MetaType
| Fable.LambdaType _
| Fable.DelegateType _
| Fable.Regex -> true
| Fable.Regex -> false
// | Fable.GenericParam(_, _, constraints) ->
// not (constraints |> List.contains Fable.Constraint.HasComparison)
| _ -> hasTypeOfType com isNonComparableType isNonComparableEntity entNames typ
// constraints |> List.contains Fable.Constraint.HasComparison
| _ -> isTypeOfType com isComparableType isComparableEntity entNames typ

let isNonComparableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface
|| not (FSharp2Fable.Util.hasStructuralComparison ent)
|| (hasFieldOfType com isNonComparableType entNames ent)
let isComparableEntity com entNames (ent: Fable.Entity) =
(FSharp2Fable.Util.hasStructuralComparison ent)
&& (hasFieldsOfType com isComparableType entNames ent)

let isNonHashableType com entNames typ =
let isHashableType com entNames typ =
match typ with
// TODO: more unhashable types?
| Fable.Any
Expand All @@ -519,13 +517,12 @@ module TypeInfo =
| Fable.MetaType
| Fable.Number((Float32 | Float64), _)
| Fable.LambdaType _
| Fable.DelegateType _ -> true
| _ -> hasTypeOfType com isNonHashableType isNonHashableEntity entNames typ
| Fable.DelegateType _ -> false
| _ -> isTypeOfType com isHashableType isHashableEntity entNames typ

let isNonHashableEntity com entNames (ent: Fable.Entity) =
ent.IsInterface
|| not (FSharp2Fable.Util.hasStructuralEquality ent)
|| (hasFieldOfType com isNonHashableType entNames ent)
let isHashableEntity com entNames (ent: Fable.Entity) =
(FSharp2Fable.Util.hasStructuralEquality ent)
&& (hasFieldsOfType com isHashableType entNames ent)

let isWrappedType com typ =
match typ with
Expand Down Expand Up @@ -3894,6 +3891,12 @@ module Util =

constraints |> List.distinct |> List.collect makeConstraint

let defaultInterfaceTypeBounds =
[
mkTypeTraitGenericBound ("core" :: "fmt" :: "Debug" :: []) None
mkTypeTraitGenericBound ("core" :: "fmt" :: "Display" :: []) None
]

let defaultTypeBounds =
[
mkTypeTraitGenericBound [ rawIdent "Clone" ] None
Expand All @@ -3902,18 +3905,17 @@ module Util =
mkLifetimeGenericBound "'static" //TODO: add it only when needed
]

let makeDefaultTypeBounds com ctx =
// let importName = getLibraryImportName com ctx "Native" "IObject"
// let objectBound = mkTypeTraitGenericBound [ importName ] None
// objectBound :: defaultTypeBounds
defaultTypeBounds
// let makeDefaultTypeBounds com ctx =
// let importName = getLibraryImportName com ctx "Native" "IObject"
// let objectBound = mkTypeTraitGenericBound [ importName ] None
// objectBound :: defaultTypeBounds

let makeGenericParams com ctx (genParams: Fable.GenericParam list) =
genParams
|> List.filter (fun p -> not p.IsMeasure)
|> List.map (fun p ->
let typeBounds = makeTypeBounds com ctx p.Name p.Constraints
let typeBounds = typeBounds @ (makeDefaultTypeBounds com ctx)
let typeBounds = typeBounds @ defaultTypeBounds
mkGenericParamFromName [] p.Name typeBounds
)

Expand All @@ -3923,7 +3925,7 @@ module Util =
function
| Fable.GenericParam(name, isMeasure, constraints) when not isMeasure ->
let typeBounds = makeTypeBounds com ctx name constraints
let typeBounds = typeBounds @ (makeDefaultTypeBounds com ctx)
let typeBounds = typeBounds @ defaultTypeBounds
mkGenericParamFromName [] name typeBounds |> Some
| _ -> None
)
Expand Down Expand Up @@ -4265,13 +4267,13 @@ module Util =
fnItem

let makeDerivedFrom com (ent: Fable.Entity) =
let isCopyable = false //not (ent |> isNonCopyableEntity com Set.empty)
let isCloneable = true //not (ent |> isNonCloneableEntity com Set.empty)
let isPrintable = not (ent |> isNonPrintableEntity com Set.empty)
let isDefaultable = not (ent |> isNonDefaultableEntity com Set.empty)
let isHashable = not (ent |> isNonHashableEntity com Set.empty)
let isEquatable = not (ent |> isNonEquatableEntity com Set.empty)
let isComparable = not (ent |> isNonComparableEntity com Set.empty)
let isCopyable = false //ent |> isCopyableEntity com Set.empty
let isCloneable = true //ent |> isCloneableEntity com Set.empty
let isPrintable = ent |> isPrintableEntity com Set.empty
let isDefaultable = ent |> isDefaultableEntity com Set.empty
let isHashable = ent |> isHashableEntity com Set.empty
let isEquatable = ent |> isEquatableEntity com Set.empty
let isComparable = ent |> isComparableEntity com Set.empty

let derivedFrom =
[
Expand Down Expand Up @@ -4528,7 +4530,7 @@ module Util =
let traitItem =
let assocItems = makeInterfaceItems com ctx false typeName ent
let generics = makeGenerics com ctx genArgs
let traitBounds = [] // (makeDefaultTypeBounds com ctx)
let traitBounds = defaultInterfaceTypeBounds
let attrs = transformAttributes com ctx ent.Attributes decl.XmlDoc
mkTraitItem attrs entName assocItems traitBounds generics

Expand All @@ -4537,7 +4539,7 @@ module Util =
let memberItems = makeInterfaceItems com ctx true typeName ent
let genArgsOpt = transformGenArgs com ctx genArgs
let traitBound = mkTypeTraitGenericBound [ entName ] genArgsOpt
let typeBounds = traitBound :: (makeDefaultTypeBounds com ctx)
let typeBounds = traitBound :: defaultInterfaceTypeBounds
let typeParam = mkGenericParamFromName [] typeName typeBounds
let genParams = makeGenericParamsFromArgs com ctx genArgs
let generics = typeParam :: genParams |> mkGenerics
Expand Down Expand Up @@ -4875,7 +4877,8 @@ module Util =
let hasToString =
nonInterfaceMembers |> List.exists (fun (d, m) -> m.CompiledName = "ToString")

makeDisplayTraitImpls com ctx entName genParams hasToString false
let hasDebug = not (List.isEmpty ent.GenericParameters)
makeDisplayTraitImpls com ctx entName genParams hasToString hasDebug

let operatorTraitImpls =
nonInterfaceMembers |> makeOpTraitImpls com ctx ent entName genArgs
Expand Down
4 changes: 2 additions & 2 deletions src/Fable.Transforms/Rust/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2367,8 +2367,8 @@ let collections (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr
let exceptions (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg with
| ".ctor", None -> bclType com ctx r t i thisArg args
| "get_Message", Some callee -> makeInstanceCall r t i callee i.CompiledName args |> Some
// | "get_StackTrace", Some e -> getFieldWith r t e "stack" |> Some
| "get_Message", Some ex -> makeInstanceCall r t i ex i.CompiledName args |> Some
| "get_StackTrace", Some ex -> makeInstanceCall r t i ex i.CompiledName args |> Some
| _ -> None

let objects (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
Expand Down
10 changes: 5 additions & 5 deletions src/fable-library-rust/src/LrcPtr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl<T: ?Sized> LrcPtr<T> {
}
}

// impl<T> Default for LrcPtr<T> {
// impl<T: ?Sized> Default for LrcPtr<T> {
// fn default() -> Self {
// Self::null()
// }
Expand Down Expand Up @@ -59,27 +59,27 @@ impl<T: ?Sized> Deref for LrcPtr<T> {
}
}

impl<T: core::fmt::Debug> core::fmt::Debug for LrcPtr<T> {
impl<T: ?Sized + core::fmt::Debug> core::fmt::Debug for LrcPtr<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:?}", self.deref())
}
}

impl<T: core::fmt::Display> core::fmt::Display for LrcPtr<T> {
impl<T: ?Sized + core::fmt::Display> core::fmt::Display for LrcPtr<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.deref())
}
}

// // Custom code within the destructor.
// impl<T: Drop> Drop for LrcPtr<T> {
// impl<T: ?Sized + Drop> Drop for LrcPtr<T> {
// fn drop(&mut self) {
// self.0.drop();
// }
// }

// Used for indexing operations (container[index])
impl<T: Index<Idx>, Idx> Index<Idx> for LrcPtr<T> {
impl<T: ?Sized + Index<Idx>, Idx> Index<Idx> for LrcPtr<T> {
type Output = T::Output;

fn index(&self, idx: Idx) -> &Self::Output {
Expand Down
Loading
Loading