diff --git a/base/compiler/abstractlattice.jl b/base/compiler/abstractlattice.jl index d98c2b818b649..0302b3f83e373 100644 --- a/base/compiler/abstractlattice.jl +++ b/base/compiler/abstractlattice.jl @@ -131,6 +131,23 @@ remaining mostly associative and commutative. """ function tmerge end +""" + tmerge_field(𝕃::AbstractLattice, a, b) -> nothing or lattice element + +Compute a lattice join of elements `a` and `b` over the lattice `𝕃`, +where `a` and `b` are fields of `PartialStruct` or `Const`. +This is an opt-in interface to allow external lattice implementation to provide its own +field-merge strategy. If it returns `nothing`, `tmerge(::PartialsLattice, ...)` +will use the default aggressive type merge implementation that does not use `tmerge` +recursively to reach convergence. +""" +function tmerge_field end + +function tmerge_field(𝕃::AbstractLattice, @nospecialize(a), @nospecialize(b)) + return tmerge_field(widenlattice(𝕃), a, b) +end +tmerge_field(::JLTypeLattice, @nospecialize(a), @nospecialize(b)) = nothing + """ ⊑(𝕃::AbstractLattice, a, b) diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index e470c4711110c..2501dd51edf6d 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -515,8 +515,12 @@ function tmerge(lattice::PartialsLattice, @nospecialize(typea), @nospecialize(ty tyi = ai elseif is_lattice_equal(lattice, bi, ft) tyi = bi + elseif (tyi′ = tmerge_field(lattice, ai, bi); tyi′ !== nothing) + # allow external lattice implementation to provide a custom field-merge strategy + tyi = tyi′ else - # Otherwise choose between using the fieldtype or some other simple merged type. + # Otherwise use the default aggressive field-merge implementation, and + # choose between using the fieldtype or some other simple merged type. # The wrapper type never has restrictions on complexity, # so try to use that to refine the estimated type too. tni = _typename(widenconst(ai))