Skip to content

Rename dispatchtuple to indivisible_type #58305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

topolarity
Copy link
Member

@topolarity topolarity commented May 2, 2025

This is hopefully a more intuitive (type-semantic) notion of what a "dispatch tuple" is.

Ideally, it makes two key properties more obvious:

  1. indivisible types are either type-equal or disjoint with each other (T == U or T != U) - they are never partially overlapping
  2. these signatures are always compilable since they are "maximally specific"

This new definition should be mostly equivalent to the existing one for Tuples, and it extends the predicate to be be analogously defined over other DataTypes (e.g. Int / Vector{Any}, which are also indivisible)

@topolarity topolarity requested a review from vtjnash May 2, 2025 13:18
@vtjnash vtjnash added the breaking This change will break code label May 2, 2025
@vtjnash
Copy link
Member

vtjnash commented May 2, 2025

This new definition point 1 might be somewhat contentious as it defines that forming Tuple{Union{}} is invalid, which is currently true, but contentious. We also are not allowed to remove public APIs. The point 2 is also not quite true either, since we have a class of malformed types that get mistakenly used in dispatch, such as Tuple{Type{Vector.body}}}, which is currently a known class of dispatch bugs and crashes.

@vtjnash
Copy link
Member

vtjnash commented May 2, 2025

(fwiw, the original name for this function was isleaftype, and it was changed to isdispatchtuple when the definition of it was last changed)

@topolarity
Copy link
Member Author

This new definition point 1 might be somewhat contentious as it defines that forming Tuple{Union{}} is invalid

I think the main refinement required is to define "indivisible" as T′ <: T implies T′ == T for all inhabited T′ (the definition is already wrong for Union{} for the same reason - thanks for pointing that out)

We also are not allowed to remove public APIs

Good point, although why this was ever a public API without a clear semantic definition is unclear to me - will add that back

The point 2 is also not quite true either, since we have a class of malformed types that get mistakenly used in dispatch, such as Tuple{Type{Vector.body}}}, which is currently a known class of dispatch bugs and crashes.

I don't think that situation is affected by this PR - malformed types seem like a separate issue

@vtjnash
Copy link
Member

vtjnash commented May 2, 2025

I don't think that situation is affected by this PR - malformed types seem like a separate issue

It means that point 2 will never be achievable, so it should not be part of the definition

@topolarity topolarity force-pushed the ct/rename-dispatchtuple branch from 73fe9dd to e5facbb Compare May 2, 2025 15:40
@topolarity
Copy link
Member Author

It means that point 2 will never be achievable, so it should not be part of the definition

Sure. It's not intended to be part of the definition, just a corollary really

I only included it because I was trying to motivate this fast-path:

julia/src/gf.c

Line 3135 in 35bfba9

int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple;

Comment on lines +2133 to +2135
@test Base.isdispatchtuple(Tuple{Tuple{Type{Union{Int,Float64}}}})
@test !Base.isdispatchtuple(Tuple{Tuple{Union{Int,Float64}}})
@test !Base.isdispatchtuple(Tuple{Tuple{DataType}})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests fail on master w/o this PR, which I assume is a bug:

@test Base.isdispatchtuple(Tuple{Tuple{Type{Union{Int,Float64}}}})
@test !Base.isdispatchtuple(Tuple{Tuple{DataType}})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those both return correct answers for me on master. What are you seeing:

julia> Base.isdispatchtuple(Tuple{Tuple{Type{Union{Int,Float64}}}})
false

julia> Base.isdispatchtuple(Tuple{Tuple{DataType}})
true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tuple{Tuple{DataType}} has a strict subtype (Tuple{Tuple{Type{Int}}}) that could appear in a call, making it not a dispatch tuple

Tuple{Tuple{Type{Union{Int,Float64}}}} has no such sub-types just like Tuple{Type{Union{Int,Float64}}} has none

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tuple{Type{Int}} is not a constructible object, so cannot appear in a call

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, that's... surprising. I didn't know that.

Anyway I think the definitions still coincide (Tuple{Type{Int}} is not inhabited so it does not affect divisibility either), so I'll update the computation to match

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I don't think our current definition is likely to remain valid for much longer (particularly the part about no subtypes or supertypes) so it is helpful to try to think about that we might replace it with. Probably at least helpful to clarify that "appear in call" means the same as "has_concrete_subtype"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does seem fatal actually...

This means that we have to refer to dispatch in this definition, since inhabited dispatch tuples != inhabited tuples (they are a strict super-set)

@topolarity topolarity removed the breaking This change will break code label May 2, 2025
This is hopefully a more intuitive (type-semantic) notion of what a
"dispatch tuple" is.

Ideally, it makes two key properties more obvious:
  1. indivisible types are either type-equal or disjoint with each other
     (T == U or T != U) - they are never partially overlapping
  2. these signatures are always compilable since they are "maximally specific"

This new definition should be mostly equivalent to the existing one for
Tuples, and it extends the predicate to be be analogously defined over
other DataTypes (e.g. `Int` / `Vector{Any}`, which are also indivisible)
@topolarity topolarity force-pushed the ct/rename-dispatchtuple branch from e5facbb to c4565ae Compare May 2, 2025 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants