Understanding type instability related to StructArrays

A minimun example in REPL:

julia> using StructArrays

julia> mutable struct Foo
           foo::Int
       end

julia> mutable struct Bar
           bar::StructArray{Foo}
       end

julia> bar = Bar(StructArray([Foo(1), Foo(2)]))
Bar(Foo[Foo(1), Foo(2)])

julia> function get_bar(bar::Bar)
           return bar.bar
       end
get_bar (generic function with 1 method)

julia> @code_warntype get_bar(bar)
MethodInstance for get_bar(::Bar)
  from get_bar(bar::Bar) in Main at REPL[5]:1
Arguments
  #self#::Core.Const(get_bar)
  bar::Bar
Body::StructArray{Foo}
1 ─ %1 = Base.getproperty(bar, :bar)::StructArray{Foo}
└──      return %1

in @code_warntype, StructArray{Foo} will be shown in red. But why is it type unstable?

ps: I found that get components from an isolated struct array is type stable. So the problem might be the use of struct array as a field of another struct. I’ve tried to change both Foo and Bar to immutable, but with no luck.

The problem is that StructArray{Foo} is an abstract type:

julia> isconcretetype(StructArray{Foo})
false

The actual type of a StructArray is complicated:

julia> typeof(StructArray([Foo(1), Foo(2)]))
StructVector{Foo, NamedTuple{(:foo,), Tuple{Vector{Int64}}}, Int64} (alias for StructArray{Foo, 1, NamedTuple{(:foo,), Tuple{Array{Int64, 1}}}, Int64})

So you’re better off using a type parameter:

mutable struct Bar{S <: StructArray{Foo}}
   bar::S
end