title: Is dispatching on value types, defined by `fieldnames` is fully determined by specialization on the type?
body: <h2>Example</h2>
  
  <p>Consider the following code which dispatches on fieldnames to determine how to combine two objects.</p>
  
  <pre><code># Rules for how to combine various fields based on there names
  combine(::Val{:foo}, foo1, foo2) = foo1+foo2
  combine(::Val{:bar}, bar1, bar2) = bar2 - bar1
  combine(::Val{:boop}, boop1, boop2) = min(boop1, boop2)
  
  # combining 2 things of the same type
  
  
  function combine(aa::T, bb::T) where T
      T(combine.(
          [Val{fn}() for fn in fieldnames(T)],
          getfield.(Ref(aa), 1:nfields(T)),
          getfield.(Ref(bb), 1:nfields(T))
          )...)
  end
  </code></pre>
  
  <p>The general pattern is useful I think
  though I'm not sure that allowing arbitrary <code>T</code> is that useful.
  It is in any case very cute, and interesting.</p>
  
  <p><strong>My question is is this going to fully determine at during
  specialization (at compile time),
  which of the field-level <code>combine</code> methods are being called?</strong></p>
  
  <h3>Demo</h3>
  
  <pre><code>julia&gt; struct Flooper
             foo::Int
             bar::Int
         end
  
  
  julia&gt; combine(Flooper(10,1), Flooper(3, 9))
  Flooper(13, 8)
  </code></pre>
  
  <p>I am struggling to read the <code>@code_warntype</code>.</p>
  
  <pre><code>julia&gt; @code_warntype combine(Flooper(10,1), Flooper(3, 9))
  Body::Any
  5 1 ── %1  = Base.Broadcast.materialize::typeof(Base.Broadcast.materialize)                             │
    │    %2  = new(Main.:(##5#6))::getfield(Main, Symbol("##5#6"))                                        │
    │    %3  = new(getfield(Base, Symbol("##9#10")){DataType}, :($(Expr(:static_parameter, 1))))::getfield(Base, Symbol("##9#10")){DataType}
    └───       goto 2 if not false                                                                        ││╻     fieldcount
    2 ┄─ %5  = π (false, Bool)                                                                            │││
    └───       goto 4 if not %5                                                                           │││
    3 ──       nothing                                                                                    │
    4 ┄─       goto 6 if not false                                                                        │││
    5 ──       nothing                                                                                    │
    6 ┄─ %10 = Base.not_int(true)::Bool                                                                   │││╻     !
    └───       goto 8 if not %10                                                                          │││
    7 ──       nothing                                                                                    │
    8 ┄─ %13 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
    │          Base.getfield(%13, :(:name))                                                               │││╻     getproperty
    │          Base.getfield(NamedTuple{names,T&lt;:Tuple}, :(:name))                                        ││││
    └───       goto 10 if not false                                                                       │││
    9 ──       nothing                                                                                    │
    10 ┄ %18 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
    │    %19 = Base.getfield(%18, :(:abstract))::Bool                                                     │││╻     getproperty
    └───       goto 12 if not %19                                                                         │││
    11 ─       goto 14                                                                                    │││
    12 ─ %22 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
    │          Base.getfield(%22, :(:name))                                                               │││╻     getproperty
    │    %24 = Base.Tuple::Type{Tuple}                                                                    │││
    │          Base.getfield(%24, :(:name))                                                               │││╻     getproperty
    └───       goto 13 if not false                                                                       │││
    13 ┄ %27 = π (false, Bool)                                                                            │││
    14 ┄ %28 = φ (11 =&gt; %19, 13 =&gt; %27)::Bool                                                             ││
    └───       goto 17 if not %28                                                                         ││╻     fieldcount
    15 ─ %30 = new(Core.ErrorException, "type does not have a definite number of fields")::ErrorException │││╻╷    error
    │          Base.throw(%30)                                                                            ││││
    └───       unreachable                                                                                ││││
    16 ─       unreachable                                                                                │││
    17 ─ %34 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
    │    %35 = Base.getfield(%34, :(:types))::Core.SimpleVector                                           │││╻     getproperty
    │    %36 = $(Expr(:gc_preserve_begin, Core.SSAValue(35)))                                             │││╻     length
    │    %37 = $(Expr(:foreigncall, :(:jl_value_ptr), Ptr{Nothing}, svec(Any), :(:ccall), 1, Core.SSAValue(35)))::Ptr{Nothing}om_objref
    │    %38 = Base.bitcast(Ptr{Int64}, %37)::Ptr{Int64}                                                  ││││╻     convert
    │    %39 = Base.pointerref(%38, 1, 1)::Int64                                                          │││││╻     unsafe_load
    │          $(Expr(:gc_preserve_end, Core.SSAValue(36)))                                               │││╻     length
    └───       goto 18                                                                                    │││
    18 ─ %42 = invoke Base.ntuple(%3::getfield(Base, Symbol("##9#10")){DataType}, %39::Int64)::Tuple      ││
    └───       goto 19                                                                                    ││
    19 ─ %44 = Base.Generator(%2, %42)::Base.Generator{_1,getfield(Main, Symbol("##5#6"))} where _1       │
    │    %45 = Base.collect(%44)::Any                                                                     │
    │    %46 = new(Base.RefValue{Flooper}, %%aa)::Base.RefValue{Flooper}                                  ││╻╷    Type
    │    %47 = Base.ifelse(true, 2, 0)::Int64                                                             ││╻╷    Type
    │    %48 = new(UnitRange{Int64}, 1, %47)::UnitRange{Int64}                                            │││
    │    %49 = Core.tuple(%46, %48)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}}                       │╻     broadcasted
    │    %50 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %49, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
    │    %51 = new(Base.RefValue{Flooper}, %%bb)::Base.RefValue{Flooper}                                  ││╻╷    Type
    │    %52 = Base.ifelse(true, 2, 0)::Int64                                                             ││╻╷    Type
    │    %53 = new(UnitRange{Int64}, 1, %52)::UnitRange{Int64}                                            │││
    │    %54 = Core.tuple(%51, %53)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}}                       │╻     broadcasted
    │    %55 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %54, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
    │    %56 = Main.combine::typeof(combine)                                                              │
    │    %57 = Base.Broadcast.broadcastable(%45)::Any                                                     │╻     broadcasted
    │    %58 = Base.Broadcast.combine_styles(%57)::Base.Broadcast.BroadcastStyle                          ││╻     combine_styles
    │    %59 = isa(%58, Base.Broadcast.DefaultArrayStyle{1})::Bool                                        │││
    └───       goto 21 if not %59                                                                         │││
    20 ─       goto 22                                                                                    │││
    21 ─ %62 = Base.Broadcast.result_style(%58, :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))))::Any│
    └───       goto 22                                                                                    │││
    22 ┄ %64 = φ (20 =&gt; :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))), 21 =&gt; %62)::Any           │││
    └───       goto 23                                                                                    │││
    23 ─ %66 = Base.Broadcast.broadcasted(%64, %56, %57, %50, %55)::Any                                   ││
    └───       goto 24                                                                                    ││
    24 ─ %68 = %1(%66)::Any                                                                               │
    │    %69 = Core._apply(:($(Expr(:static_parameter, 1))), %68)::Any                                    │
    └───       return %69       
  </code></pre>
  
  <p>I guess the alternative, if it which methods to call is not being fully determined during specialization,
  would be to rewrite it as a <code>@generated function</code>.
  But i'ld rather not it I don't have to.</p>
  
  <p>I am interested in answers for julia 0.7,
  (though 0.6 is interesting for context as I suspect this has changed slightly between the versions)</p>