2016-09-11 45 views
6

(Aktualizacja: dodałem repro przykład)Ciekawy błędy podczas łączenia inline z ograniczeniami członkowskich wyraźnych

Z kod wygląda jak następuje:

type Lib = 
    static member inline tryMe (a: ^a) = 
     let name = (^a: (static member name: string)()) 
     name 

type Test = 
    struct 
     val Value: string 
     new v = {Value = v} 
    end 
    static member inline name with get() = "HiThere" 
    static member works(a:Test) = Lib.tryMe a 

To będzie „po prostu działa” i kompilacji . Jeśli jednak przedłużyć go trochę, jak na przykład w następujący sposób:

/// Does a bounds check and raises an error if bounds check is not met 
let inline checkBounds f (g: 'b -> ^c) (tp: ^a) = 
    let convertFrom = (^a: (static member name: string)()) 
    let convertTo = (^c: (static member name : string)()) 
    let value = (^a: (member Value: 'b) tp) 
    if f value then 
     g value 
    else 
     failwithf "Cannot convert from %s to %s." convertFrom convertTo 


type ConverterA = 
    struct 
     val Value: sbyte 
     new v = { Value = v } 
    end 

    static member inline name with get() = "converter-a" 
    static member inline convert (x: ConverterA) : ConverterB = 
     checkBounds ((>=) 0y) (byte >> ConverterB) x 

and ConverterB = 
    struct 
     val Value: byte 
     new v = { Value = v } 
    end 
    static member inline name with get() = "converter-b" 

Podniesie całą masę fałszywych błędów FSharp kompilatora.

Błąd FS1114: Wartość „Foo.Bar.name” został oznaczony inline ale nie był związany w środowisku optymalizacji

Błąd FS1113: wartość „name” został oznaczony inline ale jego marki wdrożeniowe zastosowanie wewnętrznego lub prywatnego funkcji, która nie jest wystarczająco dostępny FS1116

ostrzeżenie: wartość oznaczone jako „inline” ma nieoczekiwaną wartość

błędzie FS1118: nie można wbudować t on wartość „name” oznaczone „inline”, być może dlatego, że wartość została oznaczona rekurencyjny „inline”

Nie widziałem tego dzieje się z innymi funkcjami inline. Nie jestem pewien, co się tutaj dzieje. Jeśli zmienię tylko trochę, na przykład usuń linię convertTo i jej zależności, kompiluje się ona dobrze.

Błędy również nie pojawiają się podczas uruchamiania kodu w FSI, nawet przy ustawieniu FSI z --optimize.

Mogę obejść go, usuwając inline. Dla pól tego rodzaju nie ma to większego znaczenia, JIT będzie je wstawiał, nawet jeśli F # nie ma.

Czy to błąd kompilatora? Czy jest jakiś błąd w moim kodzie lub jakieś ograniczenie dotyczące wyraźnych ograniczeń członków, których nie znałem?

Odpowiedz

1

Musisz zmienić kolejność, aby używane funkcje były znane w miejscu, w którym ich używasz, w przeciwnym razie wygląda na to, że kompilator F # nie wie, co należy wstawić. Jak powiedziałeś w komentarzach poniżej, ta odpowiedź jest błędem, jeśli mnie pytasz.

/// Does a bounds check and raises an error if bounds check is not met 
let inline checkBounds f (g: 'b -> ^c) (tp: ^a) = 
    let convertFrom = (^a: (static member name: string)()) 
    let convertTo = (^c: (static member name : string)()) 
    let value = (^a: (member Value: 'b) tp) 
    if f value then 
     g value 
    else 
     failwithf "Cannot convert from %s to %s." convertFrom convertTo 

type ConverterB = 
    struct 
     val Value: byte 
     new v = { Value = v } 
    end 
    static member inline name with get() = "converter-b" 

and ConverterA = 
    struct 
     val Value: sbyte 
     new v = { Value = v } 
    end 

    static member inline name with get() = "converter-a" 
    static member inline convert (x: ConverterA) : ConverterB = 
     checkBounds ((>=) 0y) (byte >> ConverterB) x 
+1

jak zresztą z drugiej kwestii, to rozwiązuje go jako obejście, ale nie usuwa fakt, że jest to (prawdopodobnie) błąd w F # jak porządek ma być nieistotne tutaj: [mój raport o błędzie z wczoraj] (https://github.com/Microsoft/visualfsharp/issues/1565). – Abel

+0

To prawda, dziękuję za zgłoszenie. Tak jak powiedziałem w drugim komentarzu, myślę, że kompilator nie wie, co umieścić w miejscu, w którym próbuje wstawić. – CodeMonkey