F#4中的编译器错误?

时间:2016-06-15 08:44:26

标签: 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 ->

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

  

未定义的值'oldItems:UserDisplayItem list'

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

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

我研究了构建历史,当UserDisplayItem是F#不可变记录而不是类时,它在Release中编译得很好。

Visual Studio 2015,F#4.0,任何CPU,发行版,.NET 4.5.2。

更新:

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

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 -> ()

更新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 -> ()

2 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:9)

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

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

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

// do something that doesn't get optimized away
let workaround() = null |> ignore  

然后只在正确的地方添加对函数 workaround 的调用,这是在任何出现此错误的循环之前。

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