rafaqz / Flatten.jl

Flatten nested Julia objects to tuples, and reconstruct them later
Other
32 stars 4 forks source link

Flatten.flatten is not always type stable #34

Open bgroenks96 opened 3 years ago

bgroenks96 commented 3 years ago

Unfortunately, it seems the current implementation of flatten also has type stability issues. I have yet to narrow down the exact cause, but in my present use-case, I get the following from @code_warntype:

julia> @code_warntype Flatten.flatten(strat, Flatten.flattenable, ModelParameters.SELECT, ModelParameters.IGNORE)
Variables
  #self#::Core.Const(Flatten.flatten)
  x::Stratigraphy{7, Tuple{StratComponent{Top, CompoundProcess{Tuple{CryoGrid.Processes.Boundaries.ComposedBoundaryProcess{typeof(+), Constant{Dirichlet, Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, nothing}, TemperatureGradient{NFactor{Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}}, Forcings{NamedTuple{(:Tair,), Tuple{TimeSeriesForcing{Float64, Vector{Float64}, Interpolations.GriddedInterpolation{Float64, 1, Float64, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}}}}}}}}, Dirichlet}}}, :top}, StratComponent{Soil{Sand, Float64, Nothing}, CompoundProcess{Tuple{Heat{SFCC{DallAmico{Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Int64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Float64}}}}}, Base.var"#78#79"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:T, :Tₘ, :θres, :θsat, :θtot, :L, :α, :n), CryoGrid.Numerics.var"#_RGF_ModTag", CryoGrid.Numerics.var"#_RGF_ModTag", (0x36bfdc45, 0xfd5648ac, 0xfb7948a1, 0x3f61944c, 0xaeb3da0f)}}, SFCCNewtonSolver}, CryoGrid.Processes.HeatConduction.Temperature, 7}}}, :soil1}, StratComponent{Soil{Sand, Float64, Nothing}, CompoundProcess{Tuple{Heat{SFCC{DallAmico{Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Int64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Float64}}}}}, Base.var"#78#79"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:T, :Tₘ, :θres, :θsat, :θtot, :L, :α, :n), CryoGrid.Numerics.var"#_RGF_ModTag", CryoGrid.Numerics.var"#_RGF_ModTag", (0x36bfdc45, 0xfd5648ac, 0xfb7948a1, 0x3f61944c, 0xaeb3da0f)}}, SFCCNewtonSolver}, CryoGrid.Processes.HeatConduction.Temperature, 7}}}, :soil2}, StratComponent{Soil{Sand, Float64, Nothing}, CompoundProcess{Tuple{Heat{SFCC{DallAmico{Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Int64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Float64}}}}}, Base.var"#78#79"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:T, :Tₘ, :θres, :θsat, :θtot, :L, :α, :n), CryoGrid.Numerics.var"#_RGF_ModTag", CryoGrid.Numerics.var"#_RGF_ModTag", (0x36bfdc45, 0xfd5648ac, 0xfb7948a1, 0x3f61944c, 0xaeb3da0f)}}, SFCCNewtonSolver}, CryoGrid.Processes.HeatConduction.Temperature, 7}}}, :soil3}, StratComponent{Soil{Sand, Float64, Nothing}, CompoundProcess{Tuple{Heat{SFCC{DallAmico{Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Int64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Float64}}}}}, Base.var"#78#79"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:T, :Tₘ, :θres, :θsat, :θtot, :L, :α, :n), CryoGrid.Numerics.var"#_RGF_ModTag", CryoGrid.Numerics.var"#_RGF_ModTag", (0x36bfdc45, 0xfd5648ac, 0xfb7948a1, 0x3f61944c, 0xaeb3da0f)}}, SFCCNewtonSolver}, CryoGrid.Processes.HeatConduction.Temperature, 7}}}, :soil4}, StratComponent{Soil{Sand, Float64, Nothing}, CompoundProcess{Tuple{Heat{SFCC{DallAmico{Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Int64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Int64, Float64}}}}}, Base.var"#78#79"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:T, :Tₘ, :θres, :θsat, :θtot, :L, :α, :n), CryoGrid.Numerics.var"#_RGF_ModTag", CryoGrid.Numerics.var"#_RGF_ModTag", (0x36bfdc45, 0xfd5648ac, 0xfb7948a1, 0x3f61944c, 0xaeb3da0f)}}, SFCCNewtonSolver}, CryoGrid.Processes.HeatConduction.Temperature, 7}}}, :soil5}, StratComponent{Bottom, CompoundProcess{Tuple{Constant{Neumann, Float64, nothing}}}, :bottom}}, NTuple{7, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}}}
  ft::Core.Const(FieldMetadata.flattenable)
  use::Type{AbstractParam}
  ignore::Type{AbstractDict}

Body::Tuple{Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Vararg{Any, N} where N}
1 ─       nothing
│   %2  = ($(Expr(:static_parameter, 1)) <: $(Expr(:static_parameter, 3)))::Core.Const(false)
└──       goto #3 if not %2
2 ─       Core.Const(())
└──       Core.Const(:(return %4))
3 ┄ %6  = ($(Expr(:static_parameter, 1)) <: $(Expr(:static_parameter, 2)))::Core.Const(false)
└──       goto #5 if not %6
4 ─       Core.Const(:(Core.tuple(x)))
└──       Core.Const(:(return %8))
5 ┄ %10 = Flatten._flatten::Core.Const(Flatten._flatten)
│   %11 = (%10)(x, ft, use, ignore)::Tuple{Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, NamedTuple{(:val, :units), Tuple{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}, Param{Float64, NamedTuple{(:val,), Tuple{Float64}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Param{Float64, NamedTuple{(:val, :bounds), Tuple{Float64, Tuple{Float64, Float64}}}}, Vararg{Any, N} where N}
└──       return %11

Note in particular the last line, where Vararg{Any,N} where N shows up in the type signature. This seems to be what is causing the inference failure. I think this has something to do with the use of splatting in the expression builders, but I am not sure yet.