types: compute self-referential supertypes lazily - #62847
Open
Keno wants to merge 1 commit into
Open
Conversation
Keno
commented
Aug 21, 2026
| { | ||
| jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v); | ||
| for (; t->super != t; t = t->super) | ||
| while (t != NULL && t != jl_any_type) { |
Member
Author
There was a problem hiding this comment.
This doesn't care about parameters, so this seems like it could go via typename (not that it really matters)
Member
Author
|
Probably should overload |
A struct definition whose supertype declaration recursively applies the
type being defined at structurally increasing parameters, such as
struct S{T} <: A{S{Tuple{T}}} end
has an infinite supertype graph: eagerly instantiating each level's
supertype creates the next level. Today the definition-time partial fixup
truncates that recursion by silently caching wrong supertypes — the same
interned type can permanently report `Any` or its true supertype
depending on which expression happened to construct it first, and
`supertype` disagrees with `<:`.
An instantiation created while another instantiation of the same
(supertype-self-referential) typename is in flight now defers its
supertype and completes it lazily, one level per demand
(`jl_datatype_compute_super`). Every level of the graph is correct and
independent of instantiation order. Same-parameter self-references still
tie their knot through the instantiation stack, so ordinary recursive
types are unaffected, and field types stay eager — a concrete type must
publish with its layout, so the field-type analogue of this recursion
(the `S1` case of JuliaLang#61347) is left for a follow-up.
The object-model metadata tells the truth about the deferred slot:
`DataType.super` is declared maybe-undefined, non-const, and atomic, so a
raw `getfield`/`isdefined` on an unfilled slot behaves identically in
compiled and interpreted code (undefined field), never yielding a stray
NULL. `supertype` forces the computation before the field read, keeping
`getfield`'s inference precision, and constant folding of a defined
`super` remains sound because the field is write-once (mirroring the
existing `types` handling). C supertype-chain walks that can encounter a
deferred instantiation force it in place; display-path helpers that must
not reach a safepoint stay null-tolerant.
Addresses the supertype half of JuliaLang#61347.
Assisted-by: Claude Code (Fable 5)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 A struct definition whose supertype declaration recursively applies the type being defined at structurally increasing parameters, such as
has an infinite supertype graph: eagerly instantiating each level's supertype creates the next level. Today the definition-time partial fixup truncates that recursion by silently caching wrong supertypes — the same interned type can permanently report
Anyor its true supertype depending on which expression happened to construct it first, andsupertypedisagrees with<:.With this PR, an instantiation created while another instantiation of the same (supertype-self-referential) typename is in flight now defers its supertype and completes it lazily, one level per demand (
jl_datatype_compute_super). Every level of the graph is correct and independent of instantiation order. Same-parameter self-references still tie their knot through the instantiation stack, so ordinary recursive types are unaffected, and field types stay eager — a concrete type must publish with its layout, so the field-type analogue of this recursion (theS1case of #61347) is left for a follow-up.Addresses the supertype half of #61347.
Assisted-by: Claude Code (Fable 5)