leanprover / leanprover/lean4

type theory edge case: projections and sort polymorphism

Open
#7,637 4 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P-low
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Prerequisites

Please put an X between the brackets as you perform the following steps:

Description

Using set_option bootstrap.inductiveCheckResultingUniverse false allows the creation of inductive types in Sort u that support primitive projections to types in Sort u, yet with a recursor that only allows eliminating into Prop. This means that primitive projections are currently not conservative over recursors.

Context

https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/type.20theory.20edge.20case.3A.20projections.20and.20sort.20polymorphism

Steps to Reproduce
set_option bootstrap.inductiveCheckResultingUniverse false in
set_option genSizeOf false in
set_option genInjectivity false in
inductive Wrap (α : Sort u) : Sort u
  | wrap (unwrap : α)

abbrev Wrap.unwrap {α : Sort u} (self : Wrap α) : α := self.1

/--
info: Wrap.rec.{u} {α : Sort u} {motive : Wrap α → Prop} (wrap : ∀ (unwrap : α), motive (Wrap.wrap unwrap)) (t : Wrap α) :
  motive t
-/
#guard_msgs in
#check Wrap.rec

The recursor for Wrap can only eliminate into Prop since the argument unwrap : α to the constructor is not a Prop. However, primitive projection is allowed since Wrap α : Prop only when α : Prop, and projecting a Prop field is valid. This means that the projection Wrap.unwrap cannot be expressed using the recursor Wrap.rec.

Versions

Lean 4.19.0-nightly-2025-03-22

Additional Information

There seem to be two ways to fix this discrepency between the strength of recursors and projections.
One is to disallow projections for such types, weakening projections to match the existing recursors, and the other is to allow subsingleton elimination for such types, strengthening recursors to match the existing projections.
I have implemented the latter at https://github.com/leanprover/lean4/commit/0194f054243f271ed3ec45303b41c96ef03ff307, where the subsingleton elimination check in elim_only_at_universe_zero is modified to check that the fields live in Prop for level assignments that result in the inductive type being in Prop. In the example above, this causes Wrap.rec to support non-Prop motives. This change would also allow structures like PProd and PSigma to avoid having max 1 in their sort level, which could potentially simplify metaprogramming code:

set_option bootstrap.inductiveCheckResultingUniverse false in
structure PProd' (α : Sort u) (β : Sort v) : Sort (max u v) where
  fst : α
  snd : β
Impact

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal Wrap reproduction in the issue and verify its behavior on the current nightly release. Read the linked Zulip discussion and compare the allowed primitive projection with the generated recursor. Done means resolving the discrepancy consistently and adding a regression test for the chosen behavior.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.