将内联与显式成员约束相结合时出现奇怪的错误
Curious errors when combining inline with explicit member constraints
(更新:我添加了一个重现示例)
代码如下所示:
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
这将 "just work" 并编译。但是,如果稍微扩展一下,例如如下所示:
/// 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"
它会引发一大堆虚假的 FSharp 编译器错误。
error FS1114: The value 'Foo.Bar.name' was marked
inline but was not bound in the optimization environment
error FS1113:The value 'name' was marked inline but its
implementation makes use of an internal or private function which is not
sufficiently accessible
warning FS1116: A value marked as 'inline' has an unexpected value
error FS1118: Failed to inline the value 'name'
marked 'inline', perhaps because a recursive value was marked 'inline'
我还没有看到其他内联函数发生这种情况。我不确定这里会发生什么。如果我稍微改变一点,例如删除 convertTo
行及其依赖项,它编译得很好。
当 运行 FSI 中的代码时,即使使用 --optimize
设置 FSI,也不会出现错误。
我可以通过删除 inline
来解决这个问题。对于这种类型的字段,无论如何都无关紧要,JIT 将内联它们,即使 F# 没有。
这是编译器错误吗?还是我的代码有错误,或者我没有意识到的对显式成员约束的一些限制?
您需要重新排序,以便您使用的函数在您使用它们的地方是已知的,否则看起来 F# 编译器不知道要内联什么。正如你在下面的评论中所说,如果你问我,这是一个错误。
/// 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
(更新:我添加了一个重现示例)
代码如下所示:
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
这将 "just work" 并编译。但是,如果稍微扩展一下,例如如下所示:
/// 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"
它会引发一大堆虚假的 FSharp 编译器错误。
error FS1114: The value 'Foo.Bar.name' was marked inline but was not bound in the optimization environment
error FS1113:The value 'name' was marked inline but its implementation makes use of an internal or private function which is not sufficiently accessible
warning FS1116: A value marked as 'inline' has an unexpected value
error FS1118: Failed to inline the value 'name' marked 'inline', perhaps because a recursive value was marked 'inline'
我还没有看到其他内联函数发生这种情况。我不确定这里会发生什么。如果我稍微改变一点,例如删除 convertTo
行及其依赖项,它编译得很好。
当 运行 FSI 中的代码时,即使使用 --optimize
设置 FSI,也不会出现错误。
我可以通过删除 inline
来解决这个问题。对于这种类型的字段,无论如何都无关紧要,JIT 将内联它们,即使 F# 没有。
这是编译器错误吗?还是我的代码有错误,或者我没有意识到的对显式成员约束的一些限制?
您需要重新排序,以便您使用的函数在您使用它们的地方是已知的,否则看起来 F# 编译器不知道要内联什么。正如你在下面的评论中所说,如果你问我,这是一个错误。
/// 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