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

Simple trait calls not working properly #2135

Closed
gusty opened this issue Aug 2, 2020 · 6 comments
Closed

Simple trait calls not working properly #2135

gusty opened this issue Aug 2, 2020 · 6 comments

Comments

@gusty
Copy link
Contributor

gusty commented Aug 2, 2020

Here's two small repros. The former produces a compile error and the latter a runtime error.

type Map = Map with
    static member inline InvokeOnInstance (mapping: 'T->'U) (source: '``Functor<'T>``) : '``Functor<'U>`` = 
        (^``Functor<'T>`` : (static member Map : _ * _ -> _) source, mapping)

type Identity<'t> = Identity of 't with
    static member Map (Identity x, f : 'T->'U) = Identity (f x)  : Identity<'U>
    static member run (Identity x) = x  : 'T

let setl optic value (source: 's) : 't = Identity.run (optic (fun _ -> Identity value) source)

let mapItem2 f (x, y) = (x, f y)

let inline _2 f t = Map.InvokeOnInstance (fun x -> mapItem2 (fun _ -> x) t) (* <| *) (f (snd t))
// (non trait-call) -> let inline _2 f t = (fun f x -> Identity.Map(x,f)) (fun x -> mapItem2 (fun _ -> x) t) (f (snd t))

let r2 = setl _2 42 ("hello","world")
printfn "%A" r2

Uncommenting the <| operator solves the issue, no need to mention that this is not necessary in normal F#.

Of course, exchanging the problematic line with the following non-trait call also makes it work, but that's not interesting.

The next fragment comes from this issue in the repl fable-compiler/repl#117

type First<'t> = First of Option<'t> with
    static member get_Zero () = First None : First<'t>
    static member run (First a) = a        : 't option

type Const<'t,'u> = Const of 't with
    static member inline Return (_: 'U) = Const LanguagePrimitives.GenericZero : Const<'T,'U>
    static member run (Const a) = a

let t2: int option =
    Error 1
    |> fun x ->  (^``Applicative<'T>`` : (static member Return : ^T -> ^``Applicative<'T>``) x)
    // (non trait-call) -> |> Const.Return
    |> Const.run 
    |> First.run

printfn "t2"

Here the situation is worst, as you can see in the linked issue it compiles fine but creates the wrong js code.

@alfonsogarciacaro
Copy link
Member

alfonsogarciacaro commented Nov 5, 2020

I'm getting compiler warnings when compiling these examples in .NET. For example, when compiling the second one:

warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'T has been constrained to be type 'Result<'a,int>'.
warning FS1125: The instantiation of the generic type 'Const' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'Const<_,_>'.
warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'Applicative<'T> has been constrained to be type 'Const< ^a,Result<'b,int>>'.

Would it be possible to get a sample that doesn't generate compiler warnings?

@gusty
Copy link
Contributor Author

gusty commented Nov 5, 2020

Those warnings are not a big deal, if you want to get rid of them, just make them independent functions, here's how:

type First<'t> = First of Option<'t> with
    static member get_Zero () = First None : First<'t>

module First =
    let run (First a) = a        : 't option

type Const<'t,'u> = Const of 't with
    static member inline Return (_: 'U) = Const LanguagePrimitives.GenericZero : Const<'T,'U>

module Const =
    let run (Const a) = a


let inline ret x =  (^``Applicative<'T>`` : (static member Return : ^T -> ^``Applicative<'T>``) x)

let t2: int option =
    Error 1
    |> ret
    // (non trait-call) -> |> Const.Return
    |> Const.run 
    |> First.run

printfn "t2"

@alfonsogarciacaro
Copy link
Member

alfonsogarciacaro commented Nov 5, 2020

Thanks @gusty! With latest Fable build this code seems to compile correctly and doesn't generate errors as in the Fable 2 repl. I get the same result as in .NET (t2 is None), does the generate look right? Would it be possible to turn this into a test with an assertion?

export class First$1 extends Union {
    constructor(tag, ...fields) {
        super();
        this.tag = (tag | 0);
        this.fields = fields;
    }
    cases() {
        return ["First"];
    }
}

export function First$1$reflection(gen0) {
    return union_type("QuickTest.First`1", [gen0], First$1, () => [[["Item", option_type(gen0)]]]);
}

export function First$1_get_Zero() {
    return new First$1(0, void 0);
}

export function First_run(_arg1) {
    const a = _arg1.fields[0];
    return a;
}

export class Const$2 extends Union {
    constructor(tag, ...fields) {
        super();
        this.tag = (tag | 0);
        this.fields = fields;
    }
    cases() {
        return ["Const"];
    }
}

export function Const$2$reflection(gen0, gen1) {
    return union_type("QuickTest.Const`2", [gen0, gen1], Const$2, () => [[["Item", gen0]]]);
}

export function Const_run(_arg1) {
    const a = _arg1.fields[0];
    return a;
}

export const t2 = (() => {
    let arg00$0040_1;
    let arg00$0040;
    arg00$0040 = (new Const$2(0, First$1_get_Zero()));
    arg00$0040_1 = Const_run(arg00$0040);
    return First_run(arg00$0040_1);
})();

(function () {
    const clo1 = toConsole(printf("t2 %A"));
    clo1(t2);
})();

@gusty
Copy link
Contributor Author

gusty commented Nov 6, 2020

Yes, but this is an over simplified fragment of F#+ lensing.
If you're going to include F#+ tests it would be much better test than this.

@cartermp
Copy link
Contributor

The first sample compiles now. I don't know if the produced JS is correct. The second sample produces a different JS output than initially reported.

@gusty
Copy link
Contributor Author

gusty commented Jun 27, 2021

Regarding the second sample, its first version (the one with the warnings) still doesn't work (Fable 3.2.6), it doesn't print anything.
This is not a big deal, but it's an indicator that still there's a bug somewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants