set_option maxHeartbeats 400000 in
/-- A finitely generated `p ^ ∞`-torsion module over a PID is isomorphic to a direct sum of some
  `R ⧸ R ∙ (p ^ e i)` for some `e i`.-/
theorem torsion_by_prime_power_decomposition (hN : Module.IsTorsion' N (Submonoid.powers p))
    [h' : Module.Finite R N] :
    ∃ (d : ℕ) (k : Fin d → ℕ), Nonempty <| N ≃ₗ[R] ⨁ i : Fin d, R ⧸ R ∙ p ^ (k i : ℕ) := by
  obtain ⟨d, s, hs⟩ := @Module.Finite.exists_fin _ _ _ _ _ h'; use d; clear h'
  induction' d with d IH generalizing N
  · simp only [Nat.zero_eq] at *
    -- Porting note: was `use fun i => finZeroElim i`
    use finZeroElim
    rw [Set.range_eq_empty, Submodule.span_empty] at hs
    haveI : Unique N :=
      ⟨⟨0⟩, fun x => by dsimp; rw [← Submodule.mem_bot R, hs]; exact Submodule.mem_top⟩
    haveI : IsEmpty (Fin Nat.zero) := inferInstanceAs (IsEmpty (Fin 0))
    exact ⟨0⟩
  · have : ∀ x : N, Decidable (x = 0) := fun _ => by classical infer_instance
    obtain ⟨j, hj⟩ := exists_isTorsionBy hN d.succ d.succ_ne_zero s hs
    let s' : Fin d → N ⧸ R ∙ s j := Submodule.Quotient.mk ∘ s ∘ j.succAbove
    -- Porting note(https://github.com/leanprover-community/mathlib4/issues/5732):
    -- `obtain` doesn't work with placeholders.
    have := IH ?_ s' ?_
    obtain ⟨k, ⟨f⟩⟩ := this
    clear IH
    · have : ∀ i : Fin d,
          ∃ x : N, p ^ k i • x = 0 ∧ f (Submodule.Quotient.mk x) = DirectSum.lof R _ _ i 1 := by
        intro i
        let fi := f.symm.toLinearMap.comp (DirectSum.lof _ _ _ i)
        obtain ⟨x, h0, h1⟩ := exists_smul_eq_zero_and_mk_eq hp hN hj fi; refine' ⟨x, h0, _⟩; rw [h1]
        simp only [LinearMap.coe_comp, f.symm.coe_toLinearMap, f.apply_symm_apply,
          Function.comp_apply]
      refine ⟨?_, ⟨?_⟩⟩
      · exact fun a => (fun i => (Option.rec (pOrder hN (s j)) k i : ℕ)) (finSuccEquiv d a)
      · refine (((lequivProdOfRightSplitExact
          (g := (f.trans ULift.moduleEquiv.{u, u, v}.symm).toLinearMap.comp <| mkQ _)
          (f := (DirectSum.toModule _ _ _ fun i => (liftQSpanSingleton (p ^ k i)
              (LinearMap.toSpanSingleton _ _ _) (this i).choose_spec.left : R ⧸ _ →ₗ[R] _)).comp
            ULift.moduleEquiv.toLinearMap) (R ∙ s j).injective_subtype ?_ ?_).symm.trans
          (((quotTorsionOfEquivSpanSingleton R N (s j)).symm.trans
          (quotEquivOfEq (torsionOf R N (s j)) _
          (Ideal.torsionOf_eq_span_pow_pOrder hp hN (s j)))).prod
          (ULift.moduleEquiv))).trans
          (@DirectSum.lequivProdDirectSum R _ _ _
          (fun i => R ⧸ R ∙ p ^ @Option.rec _ (fun _ => ℕ) (pOrder hN <| s j) k i) _ _).symm).trans
          (DirectSum.lequivCongrLeft R (finSuccEquiv d).symm)
        · rw [range_subtype, LinearEquiv.ker_comp, ker_mkQ]
        · rw [← f.comp_coe, LinearMap.comp_assoc, LinearMap.comp_assoc,
            LinearEquiv.toLinearMap_symm_comp_eq, LinearMap.comp_id, ← LinearMap.comp_assoc,
            ← LinearMap.comp_assoc]
          suffices (f.toLinearMap.comp (R ∙ s j).mkQ).comp _ = LinearMap.id by
            rw [this, LinearMap.id_comp]
          ext i : 3
          

Proof state:
case h.succ.intro.refine_3.intro.intro.refine_2.refine_2.H.h.h
R : Type u
inst✝⁶ : CommRing R
inst✝⁵ : IsDomain R
inst✝⁴ : IsPrincipalIdealRing R
M : Type v
inst✝³ : AddCommGroup M
inst✝² : Module R M
p : R
hp : Irreducible p
hM : IsTorsion' M ↥(Submonoid.powers p)
dec : (x : M) → Decidable (x = 0)
d : ℕ
N : Type (max u v)
inst✝¹ : AddCommGroup N
inst✝ : Module R N
hN : IsTorsion' N ↥(Submonoid.powers p)
s : Fin (Nat.succ d) → N
hs : Submodule.span R (Set.range s) = ⊤
this✝ : (x : N) → Decidable (x = 0)
j : Fin (Nat.succ d)
hj : IsTorsionBy R N (p ^ pOrder hN (s j))
s' : Fin d → N ⧸ Submodule.span R {s j} := Submodule.Quotient.mk ∘ s ∘ Fin.succAbove j
k : Fin d → ℕ
f : (N ⧸ Submodule.span R {s j}) ≃ₗ[R] ⨁ (i : Fin d), R ⧸ Submodule.span R {p ^ k i}
this :
  ∀ (i : Fin d),
    ∃ x,
      p ^ k i • x = 0 ∧
        f (Submodule.Quotient.mk x) = (DirectSum.lof R (Fin d) (fun i => R ⧸ Submodule.span R {p ^ k i}) i) 1
i : Fin d
⊢ ((((↑f ∘ₗ mkQ (Submodule.span R {s j})) ∘ₗ
            DirectSum.toModule R (Fin d) N fun i =>
              liftQSpanSingleton (p ^ k i)
                (LinearMap.toSpanSingleton R N
                  (Exists.choose
                    (_ :
                      ∃ x,
                        p ^ k i • x = 0 ∧
                          f (Submodule.Quotient.mk x) =
                            (DirectSum.lof R (Fin d) (fun i => R ⧸ Submodule.span R {p ^ k i}) i) 1)))
                (_ :
                  p ^ k i •
                      Exists.choose
                        (_ :
                          ∃ x,
                            p ^ k i • x = 0 ∧
                              f (Submodule.Quotient.mk x) =
                                (DirectSum.lof R (Fin d) (fun i => R ⧸ Submodule.span R {p ^ k i}) i) 1) =
                    0)) ∘ₗ
          DirectSum.lof R (Fin d) (fun i => R ⧸ Submodule.span R {p ^ k i}) i) ∘ₗ
        mkQ (Submodule.span R {p ^ k i}))
      1 =
    ((LinearMap.id ∘ₗ DirectSum.lof R (Fin d) (fun i => R ⧸ Submodule.span R {p ^ k i}) i) ∘ₗ
        mkQ (Submodule.span R {p ^ k i}))
      1

Next tactic:
simp only [LinearMap.coe_comp, Function.comp_apply, mkQ_apply]