Подтвердить что ты не робот

Почему у F # generic struct есть дополнительное поле __dummy?

Используя F # Interactive, вы можете проверить следующие размеры:

// sizeof<A> = 4 bytes
type A (i: int) = struct end

// sizeof<B<int>> = 8 bytes (use any type parameter)
type B<'T> (i: int) = struct end

Причиной дополнительного размера является наличие целочисленного поля __dummy в общем случае. Снова используя F # Interactive, вы можете увидеть это с помощью typeof:

  • typeof<A> показывает DeclaredFields = [|Int32 i|]
  • typeof<B<int>> показывает DeclaredFields = [|Int32 i; Int32 __dummy|]

Я не понимаю, почему это поле __dummy было добавлено.

Я думаю, что код, отвечающий за его добавление, находится здесь:

https://github.com/fsharp/FSharp.Compiler.Service/blob/master/src/fsharp/ilxgen.fs

Линия 6377 показывает следующее:

if requiresExtraField then 
    yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]

Линия 6290 - это где requiresExtraField определено:

let requiresExtraField = 
    let isEmptyStruct = 
        (match ilTypeDefKind with ILTypeDefKind.ValueType -> true | _ -> false) &&
        // All structs are sequential by default 
        // Structs with no instance fields get size 1, pack 0
        tycon.AllFieldsAsList |> List.exists (fun f -> not f.IsStatic)

    isEmptyStruct && cenv.opts.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty

Я предполагаю, что isEmptyStruct предполагается, что структура не имеет полей экземпляра. Но написанный код проверяет, имеет ли структура какие-либо поля экземпляров, которые для большинства структур, включая мои, будут истинными. Я думаю, что последняя часть финального теста заключается в том, есть ли какие-либо параметры типового типа. Итак, requiresExtraField false для type A (не общий) и true для type B (общий тип).

Является ли это ошибкой компилятора, или код правильный? Если это правильно, то какова цель этого поля __dummy? Есть ли способ избежать этого?

В качестве другого теста я удалил одно и только поле экземпляра, и неудивительно, что я получил следующие размеры, показывая, что поле __dummy больше не добавлено:

// sizeof<AA> = 1
type AA = struct end

// sizeof<BB<int>> = 1
type BB<'T> = struct end

Причина, по которой я хочу иметь тип значения, а не ссылочный тип, заключается в том, что я буду хранить много этих объектов в своих структурах данных, а не просто передавать их.

4b9b3361

Ответ 1

Объяснение дано @jyoung в комментариях ниже моего оригинального сообщения.

Последняя строка requiresExtraField также проверяет cenv.opts.workAroundReflectionEmitBugs. Этот флаг отображается в fscopts.fs. Строка кода:

workAroundReflectionEmitBugs=tcConfig.isInteractive; // REVIEW: is this still required?

Таким образом, проблема дополнительного поля __dummy возникает только в F # Interactive.