@@ -772,6 +772,12 @@ function __apply_copy_template(valp, template)
772772 return p. constant[template. idx[1 ]][template. idx[2 ]]
773773 elseif template isa ParameterIndex{Nonnumeric, Tuple{Int, UnitRange{Int}}}
774774 return p. nonnumeric[template. idx[1 ]][template. idx[2 ]]
775+ elseif template isa StaticBufferIndex{SciMLStructures. Discrete}
776+ return _static_buffer (p. discrete, template)[template. range]
777+ elseif template isa StaticBufferIndex{SciMLStructures. Constants}
778+ return _static_buffer (p. constant, template)[template. range]
779+ elseif template isa StaticBufferIndex{Nonnumeric}
780+ return _static_buffer (p. nonnumeric, template)[template. range]
775781 elseif template isa UnitRange{Int}
776782 return u[template]
777783 elseif template isa ObservedWrapper
801807struct IndepVarTemplate end
802808const IV_TEMPLATE = IndepVarTemplate ()
803809
810+ """
811+ $TYPEDEF
812+
813+ Template entry for `CopyParamsByTemplate` indexing into one of the inner buffers of a
814+ multi-buffer `MTKParameters` portion (discrete/constants/nonnumeric). Unlike
815+ `ParameterIndex{P, Tuple{Int, UnitRange{Int}}}`, the buffer index `I` is lifted into the
816+ type domain so that indexing the heterogeneously-typed tuple of buffers constant-folds and
817+ infers concretely. With a runtime buffer index the result is a small `Union` of the buffer
818+ types, which Enzyme's type analysis rejects (`IllegalTypeAnalysisException`) when it flows
819+ into `reshape` inside the `CopyParamsByTemplate` compile unit.
820+ """
821+ struct StaticBufferIndex{P, I}
822+ range:: UnitRange{Int}
823+ end
824+
825+ function StaticBufferIndex {P} (idx:: Tuple{Int, UnitRange{Int}} ) where {P}
826+ return StaticBufferIndex {P, idx[1]} (idx[2 ])
827+ end
828+
829+ @inline _static_buffer (bufs:: Tuple , :: StaticBufferIndex{P, I} ) where {P, I} = bufs[I]
830+
804831Base. @nospecializeinfer function __specialize_templates (template:: Vector{Any} , elem_types:: Set{DataType} )
805832 if length (template) <= 4
806833 return Tuple (template)
@@ -913,6 +940,18 @@ function CopyParamsByTemplate(srcsys::AbstractSystem, syms::AbstractArray{Symbol
913940 end
914941 end
915942
943+ # Lift buffer indices of multi-buffer portions (discrete/constants/nonnumeric) into
944+ # the type domain. This is done as a final pass so the contiguous-range merging above
945+ # can keep operating on plain `ParameterIndex`es.
946+ for i in eachindex (template)
947+ entry = template[i]
948+ if entry isa ParameterIndex && entry. idx isa Tuple{Int, UnitRange{Int}}
949+ delete! (elem_types, typeof (entry))
950+ template[i] = StaticBufferIndex {typeof(entry.portion)} (entry. idx)
951+ push! (elem_types, typeof (template[i]))
952+ end
953+ end
954+
916955 return CopyParamsByTemplate {true} (__specialize_templates (template, elem_types), size (syms))
917956end
918957
0 commit comments