F#4中的编译器错误?

Ben*_*erg 19 f#

我有一些F#4.0源代码在Debug中编译良好,但在Release中没有.

没有条件定义,推断类型没有变化,也没有其他我能想到的,这可以解释这个差异给我.

我是否真的偶然发现了编译器错误?

这是一个有问题的代码片段.

let oldItems = userDisplayItems |> Seq.toList
for newItem in newItems do
    match List.tryFind (fun (itemOfOld: UserDisplay.UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
    | Some oldItem ->
Run Code Online (Sandbox Code Playgroud)

错误消息指的是最后一次使用"oldItems",在长行末尾的"with"关键字之前.错误消息是:

未定义的值'oldItems:UserDisplayItem list'

什么!?oldItems在上面几行显而易见,这在Debug中编译,为什么不在Release中呢?该错误消息实际上意味着什么?

UserDisplayItem是一个简单的类.newItems是UserDisplayItem的ResizeArray

我查看了构建历史,当UserDisplayItem是F#immutable记录而不是类时,它在Release中编译得很好.

Visual Studio 2015,F#4.0,任何CPU,Release,.NET 4.5.2都是针对性的.

更新:

以下是一个完整的例子.您可以创建一个F#控制台应用程序,并将其粘贴到Program.fs中.我希望它将在Debug中编译,但不会在Release中编译.

open System.Collections.ObjectModel

type User = { Id: int }

[<AllowNullLiteral>]
type UserDisplayItem(id: int) =
    let mutable id = id
    member x.Id with get() = id and set(v) = id <- v

let userDisplayItems = new ObservableCollection<UserDisplayItem>()

let refreshList () =
    let newItems = userDisplayItems
    let oldItems = userDisplayItems |> Seq.toList
    for newItem in newItems do
        match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
        | Some oldItem -> ()
        | None -> ()
Run Code Online (Sandbox Code Playgroud)

更新2:

更短的样本.

type UserDisplayItem = { Id: int }

let refreshList () =
    let newItems = new ResizeArray<UserDisplayItem>()
    let oldItems = new ResizeArray<UserDisplayItem>() |> Seq.toList
    for newItem in newItems do
        match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
        | Some oldItem -> ()
        | None -> ()
Run Code Online (Sandbox Code Playgroud)

DAX*_*lic 10

似乎是编译器错误(可能与1020有关).
可以使用您的代码和F#版本14.0.23413.0重现它
现在安装了当前预览,它是F#版本14.0.23618.0并且它可以工作.


Ben*_*erg 9

在您解决此问题之前(请参阅DAXaholic的最终修复答案),您可以使用此解决方法,如dsyme所述:

https://github.com/Microsoft/visualfsharp/issues/759#issuecomment-162243299

该修复程序应用于问题中的最后一个示例.首先添加这个.

// do something that doesn't get optimized away
let workaround() = null |> ignore  
Run Code Online (Sandbox Code Playgroud)

然后只在正确的位置添加对函数变通方法的调用,这是在任何出现此错误的循环之前.

let oldItems = new ResizeArray<UserDisplayItem>() |> Seq.toList
workaround()
for newItem in newItems do
    match List.tryFind (fun (itemOfOld: UserDisplayItem) -> itemOfOld.Id = newItem.Id) oldItems with
Run Code Online (Sandbox Code Playgroud)