Skip to content

Use Type{T} self-types for rules on types on Julia 1.14 - #714

Merged
devmotion merged 3 commits into
mainfrom
dmw/typeegal-selftype
Oct 15, 2026
Merged

devmotion merged 3 commits into
mainfrom
dmw/typeegal-selftype

Conversation

@devmotion

Copy link
Copy Markdown
Member

Fixes #713.

On Julia 1.14, Core.Typeof(T) returns Core.TypeEgal{T} for a type T (JuliaLang/julia#62001). The rule macros use it for the function argument, so @non_differentiable/@scalar_rule/@opt_out rules on types became ambiguous with hand-written, more specific ::Type{T} rules. One example is @non_differentiable Array(::AbstractArray{Bool}) vs rrule(::Type{Array}, ::HermOrSym) in ChainRules.jl.

This PR replaces Core.Typeof with _selftype(@nospecialize(x)) = isa(x, Type) ? Type{x} : typeof(x). That is the definition of Core.Typeof up to Julia 1.13 and of Core.TypeEqOf, which lowering uses for method self-types on 1.14 (JuliaLang/julia#62287). Behaviour on Julia < 1.14 is unchanged.

I added a regression test to test/rule_definition_tools.jl. With ChainRulesCore 1.26.1 on 1.14.0-DEV.3529, the new test errors with MethodError: rrule(::Core.TypeEgal{NonDiffTypeExample}, ::Float64) is ambiguous. With this PR, the full test suite passes there.

On Julia 1.13.1 locally, one allocation test (projection.jl:462, ProjectTo(::Symmetric)) fails with 32 bytes allocated. It's unrelated to this change, and CI on main last ran before 1.13 was released.

Docs: I removed the "check which to use with Core.Typeof" tip from writing_good_rules.md, because on 1.14 it shows Core.TypeEgal{Bar}, the very signature that causes this issue. The @non_differentiable expansion example in rule_definition_tools.md now shows the defined self-type ::typeof(*).

Version bumped to 1.26.2.

🤖 Generated with Claude Code

devmotion and others added 2 commits October 15, 2026 11:21
On Julia 1.14, `Core.Typeof(T)` returns `Core.TypeEgal{T}` for a type `T`,
making macro-generated rules ambiguous with hand-written `::Type{T}` rules.

Fixes #713

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devmotion
devmotion force-pushed the dmw/typeegal-selftype branch from 5aed1d8 to 0ee77b4 Compare October 15, 2026 09:21
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.39%. Comparing base (1a236fb) to head (1f7cf23).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #714   +/-   ##
=======================================
  Coverage   93.38%   93.39%           
=======================================
  Files          15       15           
  Lines         998      999    +1     
=======================================
+ Hits          932      933    +1     
  Misses         66       66           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- `ProjectTo(::Symmetric)` returns a union of pointer-ful types, which
  is only returned unboxed since JuliaLang/julia#55045
  (1.14.0-DEV.1348). Use `broken = VERSION < v"1.14.0-DEV.1348"`
  instead of the incorrect `VERSION > v"1.13"` cutoff.
- Raise the StaticArrays test compat to 1.9.8: older versions import
  `require_one_based_indexing` from StaticArraysCore, which was removed
  in StaticArraysCore 1.4.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devmotion
devmotion merged commit 0aa1554 into main Oct 15, 2026
27 of 30 checks passed
@devmotion
devmotion deleted the dmw/typeegal-selftype branch October 15, 2026 14:46
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.

Rule macros use Core.TypeEgal self-types on Julia 1.14, causing ambiguities with ::Type{X} rules

1 participant