Skip to content

Commit de0eca8

Browse files
Temp commit
1 parent 8e9602e commit de0eca8

File tree

5 files changed

+138
-42
lines changed

5 files changed

+138
-42
lines changed

src/Fable.Core/Fable.Core.Util.fs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,44 @@ module Testing =
3939

4040

4141
module Reflection =
42-
let isUnion (x: obj): bool = nativeOnly
43-
let isRecord (x: obj): bool = nativeOnly
44-
45-
let getCaseTag (x: obj): int = nativeOnly
46-
let getCaseName (x: obj): string = nativeOnly
47-
let getCaseFields (x: obj): obj[] = nativeOnly
42+
open FSharp.Reflection
43+
44+
let isUnion (x: obj): bool =
45+
#if FABLE_COMPILER
46+
nativeOnly
47+
#else
48+
FSharpType.IsUnion(x.GetType())
49+
#endif
50+
51+
let isRecord (x: obj): bool =
52+
#if FABLE_COMPILER
53+
nativeOnly
54+
#else
55+
FSharpType.IsRecord(x.GetType())
56+
#endif
57+
58+
let getCaseTag (x: obj): int =
59+
#if FABLE_COMPILER
60+
nativeOnly
61+
#else
62+
let uci, _ = FSharpValue.GetUnionFields(x, x.GetType())
63+
uci.Tag
64+
#endif
65+
66+
let getCaseName (x: obj): string =
67+
#if FABLE_COMPILER
68+
nativeOnly
69+
#else
70+
let uci, _ = FSharpValue.GetUnionFields(x, x.GetType())
71+
uci.Name
72+
#endif
73+
74+
let getCaseFields (x: obj): obj[] =
75+
#if FABLE_COMPILER
76+
nativeOnly
77+
#else
78+
FSharpValue.GetUnionFields(x, x.GetType()) |> snd
79+
#endif
4880

4981
module Compiler =
5082
/// Compiler full version as string

src/Fable.Transforms/Dart/Replacements.fs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,17 +1484,18 @@ let nullables (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg:
14841484
| "get_HasValue", Some c -> makeEqOp r c (makeNull()) BinaryUnequal |> Some
14851485
| _ -> None
14861486

1487-
// See fable-library/Option.ts for more info on how options behave in Fable runtime
1488-
let options (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
1487+
let options isStruct (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
14891488
match i.CompiledName, thisArg with
1489+
| "get_None", _ -> NewOption(None, t.Generics.Head, isStruct) |> makeValue r |> Some
1490+
| "Some", _ -> NewOption(List.tryHead args, t.Generics.Head, isStruct) |> makeValue r |> Some
14901491
| "get_Value", Some c -> getOptionValue r t c |> Some
14911492
| "get_IsSome", Some c -> Test(c, OptionTest true, r) |> Some
14921493
| "get_IsNone", Some c -> Test(c, OptionTest false, r) |> Some
14931494
| _ -> None
14941495

1495-
let optionModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
1496+
let optionModule isStruct (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
14961497
match i.CompiledName, args with
1497-
| "None", _ -> NewOption(None, t, false) |> makeValue r |> Some
1498+
| "None", _ -> NewOption(None, t, isStruct) |> makeValue r |> Some
14981499
| "GetValue", [c] -> getOptionValue r t c |> Some
14991500
| "IsSome", [c] -> Test(c, OptionTest true, r) |> Some
15001501
| "IsNone", [c] -> Test(c, OptionTest false, r) |> Some
@@ -2708,10 +2709,11 @@ let private replacedModules =
27082709
Types.queue, bclType
27092710
Types.iset, hashSets
27102711
Types.idisposable, disposables
2711-
Types.option, options
2712-
Types.valueOption, options
2712+
Types.option, options false
2713+
Types.valueOption, options true
27132714
"System.Nullable`1", nullables
2714-
"Microsoft.FSharp.Core.OptionModule", optionModule
2715+
"Microsoft.FSharp.Core.OptionModule", optionModule false
2716+
"Microsoft.FSharp.Core.ValueOption", optionModule true
27152717
"Microsoft.FSharp.Core.ResultModule", results
27162718
Types.bigint, bigints
27172719
"Microsoft.FSharp.Core.NumericLiterals.NumericLiteralI", bigints
@@ -2892,7 +2894,7 @@ let tryType = function
28922894
Some(getNumberFullName false kind info, f, [])
28932895
| String -> Some(Types.string, strings, [])
28942896
| Tuple(genArgs, _) as t -> Some(getTypeFullName false t, tuples, genArgs)
2895-
| Option(genArg, _) -> Some(Types.option, options, [genArg])
2897+
| Option(genArg, isStruct) -> Some(Types.option, options isStruct, [genArg])
28962898
| Array(genArg,_) -> Some(Types.array, arrays, [genArg])
28972899
| List genArg -> Some(Types.list, lists, [genArg])
28982900
| Builtin kind ->

src/fable-library/Reflection.ts

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export class CaseInfo {
1818
}
1919
}
2020

21+
export const enum ErasedUnion {
22+
Default,
23+
WithTag
24+
}
25+
2126
export type EnumCase = [string, number];
2227

2328
export class MethodInfo {
@@ -32,13 +37,21 @@ export class MethodInfo {
3237
export class TypeInfo implements IEquatable<TypeInfo> {
3338
constructor(
3439
public fullname: string,
35-
public generics?: TypeInfo[],
36-
public construct?: Constructor,
37-
public parent?: TypeInfo,
38-
public fields?: () => FieldInfo[],
39-
public cases?: () => CaseInfo[],
40-
public enumCases?: EnumCase[]) {
41-
}
40+
private info?: {
41+
generics?: TypeInfo[],
42+
construct?: Constructor,
43+
parent?: TypeInfo,
44+
fields?: () => FieldInfo[],
45+
cases?: () => CaseInfo[],
46+
enumCases?: EnumCase[],
47+
}
48+
) { }
49+
public get generics() { return this.info?.generics; }
50+
public get construct() { return this.info?.construct; }
51+
public get parent() { return this.info?.parent; }
52+
public get fields() { return this.info?.fields; }
53+
public get cases() { return this.info?.cases; }
54+
public get enumCases() { return this.info?.enumCases; }
4255
public toString() {
4356
return fullName(this);
4457
}
@@ -83,59 +96,74 @@ export function class_type(
8396
generics?: TypeInfo[],
8497
construct?: Constructor,
8598
parent?: TypeInfo): TypeInfo {
86-
return new TypeInfo(fullname, generics, construct, parent);
99+
return new TypeInfo(fullname, { generics, construct, parent });
87100
}
88101

89102
export function record_type(
90103
fullname: string,
91104
generics: TypeInfo[],
92105
construct: Constructor,
93106
fields: () => FieldInfo[]): TypeInfo {
94-
return new TypeInfo(fullname, generics, construct, undefined, fields);
107+
return new TypeInfo(fullname, { generics, construct, fields });
95108
}
96109

97110
export function anonRecord_type(...fields: FieldInfo[]): TypeInfo {
98-
return new TypeInfo("", undefined, undefined, undefined, () => fields);
111+
return new TypeInfo("", { fields: () => fields });
99112
}
100113

101114
export function union_type(
102115
fullname: string,
103116
generics: TypeInfo[],
104117
construct: Constructor,
105118
cases: () => FieldInfo[][]): TypeInfo {
106-
const t: TypeInfo = new TypeInfo(fullname, generics, construct, undefined, undefined, () => {
107-
const caseNames = construct.prototype.cases() as string[];
108-
return cases().map((fields, i) => new CaseInfo(t, i, caseNames[i], fields))
119+
const t: TypeInfo = new TypeInfo(fullname, {
120+
generics,
121+
construct,
122+
cases() {
123+
const caseNames = construct.prototype.cases() as string[];
124+
return cases().map((fields, i) => new CaseInfo(t, i, caseNames[i], fields))
125+
}
109126
});
110127
return t;
111128
}
112129

113130
export function tuple_type(...generics: TypeInfo[]): TypeInfo {
114-
return new TypeInfo("System.Tuple`" + generics.length, generics);
131+
return new TypeInfo("System.Tuple`" + generics.length, { generics });
115132
}
116133

117134
export function delegate_type(...generics: TypeInfo[]): TypeInfo {
118-
return new TypeInfo("System.Func`" + generics.length, generics);
135+
return new TypeInfo("System.Func`" + generics.length, { generics });
119136
}
120137

121138
export function lambda_type(argType: TypeInfo, returnType: TypeInfo): TypeInfo {
122-
return new TypeInfo("Microsoft.FSharp.Core.FSharpFunc`2", [argType, returnType]);
139+
return new TypeInfo("Microsoft.FSharp.Core.FSharpFunc`2", {
140+
generics: [argType, returnType]
141+
});
123142
}
124143

125144
export function option_type(generic: TypeInfo): TypeInfo {
126-
return new TypeInfo("Microsoft.FSharp.Core.FSharpOption`1", [generic]);
145+
return new TypeInfo("Microsoft.FSharp.Core.FSharpOption`1", {
146+
generics: [generic]
147+
});
127148
}
128149

129150
export function list_type(generic: TypeInfo): TypeInfo {
130-
return new TypeInfo("Microsoft.FSharp.Collections.FSharpList`1", [generic]);
151+
return new TypeInfo("Microsoft.FSharp.Collections.FSharpList`1", {
152+
generics: [generic]
153+
});
131154
}
132155

133156
export function array_type(generic: TypeInfo): TypeInfo {
134-
return new TypeInfo("[]", [generic]);
157+
return new TypeInfo("[]", {
158+
generics: [generic]
159+
});
135160
}
136161

137162
export function enum_type(fullname: string, underlyingType: TypeInfo, enumCases: EnumCase[]): TypeInfo {
138-
return new TypeInfo(fullname, [underlyingType], undefined, undefined, undefined, undefined, enumCases);
163+
return new TypeInfo(fullname, {
164+
generics: [underlyingType],
165+
enumCases
166+
});
139167
}
140168

141169
export function measure_type(fullname: string): TypeInfo {
@@ -262,7 +290,9 @@ export function isInstanceOfType(t: TypeInfo, o: any) {
262290
* but it should be enough for type comparison purposes
263291
*/
264292
export function getGenericTypeDefinition(t: TypeInfo) {
265-
return t.generics == null ? t : new TypeInfo(t.fullname, t.generics.map(() => obj_type));
293+
return t.generics == null ? t : new TypeInfo(t.fullname, {
294+
generics: t.generics.map(() => obj_type)
295+
});
266296
}
267297

268298
export function getEnumUnderlyingType(t: TypeInfo) {
@@ -452,12 +482,13 @@ export function makeTuple(values: any[], _t: TypeInfo): any {
452482

453483
export function makeGenericType(t: TypeInfo, generics: TypeInfo[]): TypeInfo {
454484
return new TypeInfo(
455-
t.fullname,
456-
generics,
457-
t.construct,
458-
t.parent,
459-
t.fields,
460-
t.cases);
485+
t.fullname, {
486+
generics,
487+
construct: t.construct,
488+
parent: t.parent,
489+
fields: t.fields,
490+
cases: t.cases
491+
});
461492
}
462493

463494
export function createInstance(t: TypeInfo, consArgs?: any[]): any {

src/quicktest/QuickTest.fs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,13 @@ let measureTime (f: unit -> unit): unit = emitJsStatement () """
7979
// testCase "Addition works" <| fun () ->
8080
// 2 + 2 |> equal 4
8181

82-
[<Erase>]
82+
// [<Erase>]
8383
type MyRecord =
8484
{ Foo: int }
8585

86+
type MyRecord2 =
87+
{ Bar: MyRecord }
88+
8689
let testMyRecord (r: MyRecord) =
8790
r.Foo
8891

@@ -100,6 +103,18 @@ let test = function
100103
Zas 5.67890 |> test |> printfn "%s"
101104
Foo("oh", 3) |> test |> printfn "%s"
102105

106+
[<Erase>]
107+
type WrappedNum = Num of int with
108+
static member ( + ) (Num x, Num y) = 2 * (x + y) |> Num
109+
110+
let add1 (x: WrappedNum) y = x + y
111+
112+
let add2 (x: WrappedNum) y = x + Num y
113+
114+
testCase "Can resolve custom operators on erased types" <| fun () -> // See #2915
115+
add1 (Num 4) (Num 5) |> equal (Num 18)
116+
add2 (Num 4) 5 |> equal (Num 18)
117+
103118
(*
104119
module TaggedUnion =
105120
type Base<'Kind> =

tests/Js/Main/OptionTests.fs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ let tests =
8080
Option.isNone o2 |> equal false
8181
Option.isSome o2 |> equal true
8282

83+
testCase "ValueOption.isSome/isNone works" <| fun () ->
84+
let o1: int voption = ValueNone
85+
let o2 = ValueSome 5
86+
ValueOption.isNone o1 |> equal true
87+
ValueOption.isSome o1 |> equal false
88+
ValueOption.isNone o2 |> equal false
89+
ValueOption.isSome o2 |> equal true
90+
8391
testCase "Option.IsSome/IsNone works" <| fun () ->
8492
let o1 = None
8593
let o2 = Some 5
@@ -88,6 +96,14 @@ let tests =
8896
o2.IsNone |> equal false
8997
o2.IsSome |> equal true
9098

99+
testCase "ValueOption.IsSome/IsNone works" <| fun () ->
100+
let o1: int voption = ValueNone
101+
let o2 = Some 5
102+
o1.IsNone |> equal true
103+
o1.IsSome |> equal false
104+
o2.IsNone |> equal false
105+
o2.IsSome |> equal true
106+
91107
testCase "Option.iter works" <| fun () -> // See #198
92108
let mutable res = false
93109
let getOnlyOnce =

0 commit comments

Comments
 (0)