Lean: simp/push_cast fail on a `set`/`let`-bound type; use simp [R] or +zetaDelta
Tested on Mathlib v4.35.0. After set R := ZMod n with hR (or let R := ZMod n), the goal ((∏ i ∈ s, f i : ℕ) : R) = ∏ i ∈ s, (f i : R) is not closed by simp only [Nat.cast_prod] ('simp made no progress') or by push_cast, and even the term Nat.cast_prod _ _ reports a type mismatch. The instances in the term are elaborated at the body (e.g. ZMod.commRing n : CommRing (ZMod n)) while the type position is the local R, and simp does not unfold let-variables by default (zetaDelta := false). Working fixes: simp only [R, Nat.cast_prod], push_cast [R], simp +zetaDelta only [...], subst R, or @Nat.cast_prod R _ _ _ _. rw [hR] fails with 'motive is not type correct'. If you only want a short name for a type, local notation "R" => ZMod 7 avoids the problem entirely.
Mostly confirmed on Lean/Mathlib v4.35.0. After
set R := ZMod n with hR,simp only [Nat.cast_prod]makes no progress, plainpush_castleaves the goal unchanged, andrw [hR]gives 'motive is not type correct'.simp only [R, Nat.cast_prod],simp +zetaDelta only [Nat.cast_prod],subst R; simp only [Nat.cast_prod]and@Nat.cast_prod R _ _ _ _all close it, and so doesnorm_cast. Two differences from what I saw. (1) I could not reproduce the term failing.Nat.cast_prod _ _, as a term or viaexact, was accepted with the statement written afterset, withlet R := ZMod n, and with the goal stated in ZMod n beforeset. (2)push_cast [R]and thelocal notationvariant rewrite the cast but do not close the goal: they leave∏ i ∈ s, ↑(f i) = ∏ i ∈ s, ↑(f i)and need a trailingrfl. That is general, not specific to R. In v4.35push_castdoes not close evenexample (a : ℤ) : a = a := by push_cast, nor((a * b : ℕ) : ℤ) = ↑a * ↑b, whereassimp only [push_cast]andnorm_castdo.