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

Fix broken --precompiledLib switch #3817

Merged
8 changes: 8 additions & 0 deletions src/Fable.AST/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Removed

* Remove `MemberRefInfo.Attributes` [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) (by @DunetsNM)

### Added

* Add `MemberRefInfo.AttributeFullNames` [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) (by @DunetsNM)

## 4.4.0 - 2024-02-13

### Changed
Expand Down
48 changes: 45 additions & 3 deletions src/Fable.AST/Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ type MemberRefInfo =
IsInstance: bool
CompiledName: string
NonCurriedArgTypes: Type list option
Attributes: Attribute seq
// We only store the attributes fullname otherwise deserialization of precompiled files fails
// System.Text.Json is not able to deserialize the standard Attribute type because it is an interface
// More about it here: https://github.com/fable-compiler/Fable/pull/3817
AttributeFullNames: string list
}

type MemberRef =
Expand Down Expand Up @@ -482,6 +485,26 @@ type ArrayKind =
| MutableArray
| ImmutableArray

[<RequireQualifiedAccess>]
type NumberValue =
| Int8 of sbyte
| UInt8 of byte
| Int16 of int16
| UInt16 of System.UInt16
| Int32 of System.Int32
| UInt32 of System.UInt32
| Int64 of System.Int64
| UInt64 of System.UInt64
| Int128 of upper: System.UInt64 * lower: System.UInt64 // System.Int128
| UInt128 of upper: System.UInt64 * lower: System.UInt64 // System.UInt128
| BigInt of bigint
| NativeInt of nativeint
| UNativeInt of unativeint
| Float16 of System.Single // System.Half
| Float32 of System.Single
| Float64 of System.Double
| Decimal of System.Decimal

type ValueKind =
// The AST from F# compiler is a bit inconsistent with ThisValue and BaseValue.
// ThisValue only appears in constructors and not in instance members (where `this` is passed as first argument)
Expand All @@ -497,7 +520,7 @@ type ValueKind =
/// String interpolation with support for JS tagged templates
/// String parts length should always be values.Length + 1
| StringTemplate of tag: Expr option * parts: string list * values: Expr list
| NumberConstant of value: obj * kind: NumberKind * info: NumberInfo
| NumberConstant of value: NumberValue * info: NumberInfo
| RegexConstant of source: string * flags: RegexFlag list
| NewOption of value: Expr option * typ: Type * isStruct: bool
| NewArray of newKind: NewArrayKind * typ: Type * kind: ArrayKind
Expand All @@ -518,7 +541,26 @@ type ValueKind =
| CharConstant _ -> Char
| StringConstant _
| StringTemplate _ -> String
| NumberConstant(_, kind, info) -> Number(kind, info)
| NumberConstant(value, info) ->
match value with
| NumberValue.Int8 _ -> NumberKind.Int8
| NumberValue.UInt8 _ -> NumberKind.UInt8
| NumberValue.Int16 _ -> NumberKind.Int16
| NumberValue.UInt16 _ -> NumberKind.UInt16
| NumberValue.Int32 _ -> NumberKind.Int32
| NumberValue.UInt32 _ -> NumberKind.UInt32
| NumberValue.Int64 _ -> NumberKind.Int64
| NumberValue.UInt64 _ -> NumberKind.UInt64
| NumberValue.Int128 _ -> NumberKind.Int128
| NumberValue.UInt128 _ -> NumberKind.UInt128
| NumberValue.BigInt _ -> NumberKind.BigInt
| NumberValue.NativeInt _ -> NumberKind.NativeInt
| NumberValue.UNativeInt _ -> NumberKind.UNativeInt
| NumberValue.Float16 _ -> NumberKind.Float16
| NumberValue.Float32 _ -> NumberKind.Float32
| NumberValue.Float64 _ -> NumberKind.Float64
| NumberValue.Decimal _ -> NumberKind.Decimal
|> fun kind -> Number(kind, info)
| RegexConstant _ -> Regex
| NewOption(_, t, isStruct) -> Option(t, isStruct)
| NewArray(_, t, k) -> Array(t, k)
Expand Down
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

* [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) [All] Fix broken --precompiledLib switch (#3818) (by @DunetsNM)
* [JS/TS] Fixed TimeSpan.FromMilliseconds (#3815) (by @ncave)

## 4.17.0 - 2024-04-23
Expand Down
32 changes: 15 additions & 17 deletions src/Fable.Transforms/Dart/Fable2Dart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -719,22 +719,20 @@ module Util =
|> Expression.identExpression
|> getParts t parts

let transformNumberLiteral com r kind (x: obj) =
match kind, x with
| Dart.Replacements.DartInt, (:? char as x) -> Expression.integerLiteral (int64 x)
| Int8, (:? int8 as x) -> Expression.integerLiteral (int64 x)
| UInt8, (:? uint8 as x) -> Expression.integerLiteral (int64 x)
| Int16, (:? int16 as x) -> Expression.integerLiteral (int64 x)
| UInt16, (:? uint16 as x) -> Expression.integerLiteral (int64 x)
| Int32, (:? int32 as x) -> Expression.integerLiteral (x)
| UInt32, (:? uint32 as x) -> Expression.integerLiteral (int64 x)
| Int64, (:? int64 as x) -> Expression.integerLiteral (x)
| UInt64, (:? uint64 as x) -> Expression.integerLiteral (int64 x)
| Float32, (:? float32 as x) -> Expression.doubleLiteral (float x)
| Float64, (:? float as x) -> Expression.doubleLiteral (x)
| _ ->
$"Expected literal of type %A{kind} but got {x.GetType().FullName}"
|> addErrorAndReturnNull com r
let transformNumberLiteral com (r: Option<SourceLocation>) (v: Fable.NumberValue) =
match v with
| Fable.NumberValue.Int8 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.UInt8 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.Int16 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.UInt16 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.Int32 x -> Expression.integerLiteral (x)
| Fable.NumberValue.UInt32 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.Int64 x -> Expression.integerLiteral (x)
| Fable.NumberValue.UInt64 x -> Expression.integerLiteral (int64 x)
| Fable.NumberValue.Float16 x -> Expression.doubleLiteral (float x)
| Fable.NumberValue.Float32 x -> Expression.doubleLiteral (float x)
| Fable.NumberValue.Float64 x -> Expression.doubleLiteral (x)
| _ -> $"Numeric literal is not supported: %A{v}" |> addErrorAndReturnNull com r

let transformTuple (com: IDartCompiler) ctx (args: Expression list) =
let tup = List.length args |> getTupleTypeIdent com ctx
Expand Down Expand Up @@ -777,7 +775,7 @@ module Util =

// Dart enums are limited as we cannot set arbitrary values or combine them as flags
// so for now we compile F# enums as integers
| Fable.NumberConstant(x, kind, _) -> transformNumberLiteral com r kind x |> resolveExpr returnStrategy
| Fable.NumberConstant(x, _) -> transformNumberLiteral com r x |> resolveExpr returnStrategy

| Fable.RegexConstant(source, flags) ->
let flagToArg =
Expand Down
14 changes: 9 additions & 5 deletions src/Fable.Transforms/Dart/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ let coreModFor =
| BclKeyValuePair _ -> FableError "Cannot decide core module" |> raise

let makeLongInt com r t signed (x: uint64) =
let lowBits = NumberConstant(float (uint32 x), Float64, NumberInfo.Empty)
let highBits = NumberConstant(float (x >>> 32), Float64, NumberInfo.Empty)
let lowBits =
NumberConstant(NumberValue.Float64(float (uint32 x)), NumberInfo.Empty)

let highBits =
NumberConstant(NumberValue.Float64(float (x >>> 32)), NumberInfo.Empty)

let unsigned = BoolConstant(not signed)

let args =
Expand Down Expand Up @@ -544,7 +548,7 @@ let rec getZero (com: ICompiler) (ctx: Context) (t: Type) =
| String -> makeStrConst "" // Using empty string instead of null so Dart doesn't complain
| Number(BigInt, _) as t -> Helper.LibCall(com, "BigInt", "fromInt32", t, [ makeIntConst 0 ])
| Number(Decimal, _) as t -> makeIntConst 0 |> makeDecimalFromExpr com None t
| Number(kind, uom) -> NumberConstant(getBoxedZero kind, kind, uom) |> makeValue None
| Number(kind, uom) -> NumberConstant(NumberValue.GetZero kind, uom) |> makeValue None
| Builtin(BclTimeSpan | BclTimeOnly) -> getZeroTimeSpan t
| Builtin BclDateTime as t -> Helper.LibCall(com, "Date", "minValue", t, [])
| Builtin BclDateTimeOffset as t -> Helper.LibCall(com, "DateOffset", "minValue", t, [])
Expand All @@ -563,7 +567,7 @@ let getOne (com: ICompiler) (ctx: Context) (t: Type) =
| Boolean -> makeBoolConst true
| Number(BigInt, _) as t -> Helper.LibCall(com, "BigInt", "fromInt32", t, [ makeIntConst 1 ])
| Number(Decimal, _) as t -> makeIntConst 1 |> makeDecimalFromExpr com None t
| Number(kind, uom) -> NumberConstant(getBoxedOne kind, kind, uom) |> makeValue None
| Number(kind, uom) -> NumberConstant(NumberValue.GetOne kind, uom) |> makeValue None
| ListSingleton(CustomOp com ctx None t "get_One" [] e) -> e
| _ -> makeIntConst 1

Expand Down Expand Up @@ -2078,7 +2082,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op
| "IsInfinity", [ _ ] when isFloat ->
Helper.LibCall(com, "Double", "isInfinity", t, args, i.SignatureArgTypes, genArgs = i.GenericArgs, ?loc = r)
|> Some
| ("Parse" | "TryParse") as meth, str :: NumberConst(:? int as style, _, _) :: _ ->
| ("Parse" | "TryParse") as meth, str :: NumberConst(NumberValue.Int32 style, _) :: _ ->
let hexConst = int System.Globalization.NumberStyles.HexNumber
let intConst = int System.Globalization.NumberStyles.Integer

Expand Down
28 changes: 25 additions & 3 deletions src/Fable.Transforms/FSharp2Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1422,7 +1422,19 @@ module TypeHelpers =
// TODO: Check it's effectively measure?
// TODO: Raise error if we cannot get the measure fullname?
match tryDefinition genArgs[0] with
| Some(_, Some fullname) -> fullname
| Some(_, Some fullname) ->
// Not sure why, but when precompiling F# changes measure types to MeasureProduct<'M, MeasureOne>
match fullname with
| Types.measureProduct2 ->
match
(nonAbbreviatedType genArgs[0]).GenericArguments
|> Seq.map (tryDefinition >> Option.bind snd)
|> List.ofSeq
with
// TODO: generalize it to support aggregate units such as <m/s> or more complex
| [ Some measure; Some Types.measureOne ] -> measure
| _ -> fullname
| _ -> fullname
| _ -> Naming.unknown
else
Naming.unknown
Expand Down Expand Up @@ -2147,13 +2159,18 @@ module Util =
let fableMemberFunctionOrValue =
FsMemberFunctionOrValue(memb) :> Fable.MemberFunctionOrValue

let attributeFullNames =
fableMemberFunctionOrValue.Attributes
|> Seq.map (fun attr -> attr.Entity.FullName)
|> List.ofSeq

Fable.MemberRef(
FsEnt.Ref(ent),
{
CompiledName = memb.CompiledName
IsInstance = memb.IsInstanceMember
NonCurriedArgTypes = nonCurriedArgTypes
Attributes = fableMemberFunctionOrValue.Attributes
AttributeFullNames = attributeFullNames
}
)
| ent ->
Expand Down Expand Up @@ -2182,13 +2199,18 @@ module Util =
let fableMemberFunctionOrValue =
FsMemberFunctionOrValue(memb) :> Fable.MemberFunctionOrValue

let attributeFullNames =
fableMemberFunctionOrValue.Attributes
|> Seq.map (fun attr -> attr.Entity.FullName)
|> List.ofSeq

Fable.MemberRef(
FsEnt.Ref(ent),
{
CompiledName = memb.CompiledName
IsInstance = memb.IsInstanceMember
NonCurriedArgTypes = None
Attributes = fableMemberFunctionOrValue.Attributes
AttributeFullNames = attributeFullNames
}
)
| ent ->
Expand Down
45 changes: 22 additions & 23 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1613,27 +1613,26 @@ module Util =
let values = values |> List.mapToArray (fun e -> com.TransformAsExpr(ctx, e))

StringTemplate(tag, List.toArray parts, values, r) |> Literal
| Fable.NumberConstant(x, kind, _) ->
match kind, x with
| Decimal, (:? decimal as x) -> JS.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx
| BigInt, (:? bigint as x) -> Expression.bigintLiteral (string<bigint> x, ?loc = r)
| Int64, (:? int64 as x) -> Expression.bigintLiteral (string<int64> x, ?loc = r)
| UInt64, (:? uint64 as x) -> Expression.bigintLiteral (string<uint64> x, ?loc = r)
// | Int128, (:? System.Int128 as x) -> Expression.bigintLiteral(string x, ?loc=r)
// | UInt128, (:? System.UInt128 as x) -> Expression.bigintLiteral(string x, ?loc=r)
| NativeInt, (:? nativeint as x) -> Expression.bigintLiteral (string<nativeint> x, ?loc = r)
| UNativeInt, (:? unativeint as x) -> Expression.bigintLiteral (string<unativeint> x, ?loc = r)
| Int8, (:? int8 as x) -> Expression.numericLiteral (float x, ?loc = r)
| UInt8, (:? uint8 as x) -> Expression.numericLiteral (float x, ?loc = r)
| Int16, (:? int16 as x) -> Expression.numericLiteral (float x, ?loc = r)
| UInt16, (:? uint16 as x) -> Expression.numericLiteral (float x, ?loc = r)
| Int32, (:? int32 as x) -> Expression.numericLiteral (float x, ?loc = r)
| UInt32, (:? uint32 as x) -> Expression.numericLiteral (float x, ?loc = r)
// | Float16, (:? System.Half as x) -> Expression.numericLiteral(float x, ?loc=r)
| Float32, (:? float32 as x) -> Expression.numericLiteral (float x, ?loc = r)
| Float64, (:? float as x) -> Expression.numericLiteral (float x, ?loc = r)
| _, (:? char as x) -> Expression.numericLiteral (float x, ?loc = r)
| _ -> addErrorAndReturnNull com r $"Numeric literal is not supported: {x.GetType().FullName}"
| Fable.NumberConstant(v, _) ->
match v with
| Fable.NumberValue.Int8 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.UInt8 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Int16 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.UInt16 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Int32 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.UInt32 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Int64 x -> Expression.bigintLiteral (string<int64> x, ?loc = r)
| Fable.NumberValue.UInt64 x -> Expression.bigintLiteral (string<uint64> x, ?loc = r)
// | Fable.NumberValue.Int128(u,l) -> Expression.bigintLiteral(string System.Int128(u,l), ?loc=r)
// | Fable.NumberValue.UInt128(u,l) -> Expression.bigintLiteral(string System.UInt128(u,l), ?loc=r)
| Fable.NumberValue.BigInt x -> Expression.bigintLiteral (string<bigint> x, ?loc = r)
| Fable.NumberValue.NativeInt x -> Expression.bigintLiteral (string<nativeint> x, ?loc = r)
| Fable.NumberValue.UNativeInt x -> Expression.bigintLiteral (string<unativeint> x, ?loc = r)
| Fable.NumberValue.Float16 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Float32 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Float64 x -> Expression.numericLiteral (float x, ?loc = r)
| Fable.NumberValue.Decimal x -> JS.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx
| _ -> addErrorAndReturnNull com r $"Numeric literal is not supported: %A{v}"
| Fable.RegexConstant(source, flags) -> Expression.regExpLiteral (source, flags, ?loc = r)
| Fable.NewArray(newKind, typ, kind) ->
match newKind with
Expand Down Expand Up @@ -1914,8 +1913,8 @@ module Util =
match callInfo.MemberRef with
| Some(Fable.MemberRef(_, info)) ->
let hasParamObjectAttribute =
info.Attributes
|> Seq.tryFind (fun attr -> attr.Entity.FullName = Atts.paramObject)
info.AttributeFullNames
|> List.tryFind (fun attr -> attr = Atts.paramObject)
|> Option.isSome

if hasParamObjectAttribute then
Expand Down
8 changes: 4 additions & 4 deletions src/Fable.Transforms/FableTransforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ module private Transforms =
| Value(BoolConstant a, _), Value(BoolConstant b, _) -> Some(a = b)
| Value(CharConstant a, _), Value(CharConstant b, _) -> Some(a = b)
| Value(StringConstant a, _), Value(StringConstant b, _) -> Some(a = b)
| Value(NumberConstant(a, _, _), _), Value(NumberConstant(b, _, _), _) -> Some(a = b)
| Value(NumberConstant(a, _), _), Value(NumberConstant(b, _), _) -> Some(a = b)
| Value(NewOption(None, _, _), _), Value(NewOption(None, _, _), _) -> Some true
| Value(NewOption(Some a, _, _), _), Value(NewOption(Some b, _, _), _) -> tryEqualsAtCompileTime a b
| _ -> None
Expand All @@ -440,9 +440,9 @@ module private Transforms =
| Value(StringConstant v1, r1), Value(StringConstant v2, r2) ->
Value(StringConstant(v1 + v2), addRanges [ r1; r2 ])
// Assume NumberKind and NumberInfo are the same
| Value(NumberConstant(:? int as v1, AST.Int32, NumberInfo.Empty), r1),
Value(NumberConstant(:? int as v2, AST.Int32, NumberInfo.Empty), r2) ->
Value(NumberConstant(v1 + v2, AST.Int32, NumberInfo.Empty), addRanges [ r1; r2 ])
| Value(NumberConstant(NumberValue.Int32 v1, NumberInfo.Empty), r1),
Value(NumberConstant(NumberValue.Int32 v2, NumberInfo.Empty), r2) ->
Value(NumberConstant(NumberValue.Int32(v1 + v2), NumberInfo.Empty), addRanges [ r1; r2 ])
| _ -> e

| Operation(Logical(AST.LogicalAnd, (Value(BoolConstant b, _) as v1), v2), [], _, _) ->
Expand Down
4 changes: 3 additions & 1 deletion src/Fable.Transforms/OverloadSuffix.fs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ let rec private getTypeFastFullName (genParams: IDictionary<_, _>) (t: Fable.Typ
let genArgs = genArgs |> Seq.mapToList (getTypeFastFullName genParams)
// Not sure why, but when precompiling F# changes measure types to MeasureProduct<'M, MeasureOne>
match tdef.FullName, genArgs with
| Types.measureProduct2, [ measure; Types.measureOne ] -> measure
| Types.measureProduct2, [ measure; Types.measureOne ] ->
// TODO: generalize it to support aggregate units such as <m/s> or more complex
measure
| _ ->
let genArgs = String.concat "," genArgs

Expand Down
Loading
Loading