-- Mathlib/CategoryTheory/Adhesive.lean
theorem is_coprod_iff_isPushout {X E Y YE : C} (c : BinaryCofan X E) (hc : IsColimit c) {f : X ⟶ Y}
    {iY : Y ⟶ YE} {fE : c.pt ⟶ YE} (H : CommSq f c.inl iY fE) :
    Nonempty (IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)) ↔ IsPushout f c.inl iY fE

Proof state:
case mp.intro.refine_1
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
⊢ fE ≫ h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl) = s.ι.app WalkingSpan.right

Tactic:
apply BinaryCofan.IsColimit.hom_ext hc

Result:
case mp.intro.refine_1.h₁
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
⊢ c.inl ≫ fE ≫ h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl) = c.inl ≫ s.ι.app WalkingSpan.right

case mp.intro.refine_1.h₂
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
⊢ c.inr ≫ fE ≫ h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl) = c.inr ≫ s.ι.app WalkingSpan.right

Proof state:
case mp
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
⊢ Nonempty (IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)) → IsPushout f c.inl iY fE

Tactic:
rintro ⟨h⟩

Result:
case mp.intro
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
⊢ IsPushout f c.inl iY fE

Proof state:
case mp.intro
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
⊢ IsPushout f c.inl iY fE

Tactic:
refine ⟨H, ⟨Limits.PushoutCocone.isColimitAux' _ ?_⟩⟩

Result:
case mp.intro
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
⊢ (s : PushoutCocone f c.inl) →
    { l //
      (PushoutCocone.mk iY fE ⋯).inl ≫ l = s.inl ∧
        (PushoutCocone.mk iY fE ⋯).inr ≫ l = s.inr ∧
          ∀ {m : (PushoutCocone.mk iY fE ⋯).pt ⟶ s.pt},
            (PushoutCocone.mk iY fE ⋯).inl ≫ m = s.inl → (PushoutCocone.mk iY fE ⋯).inr ≫ m = s.inr → m = l }

Proof state:
case mpr.uniq.h₁
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H✝ : CommSq f c.inl iY fE
H : IsPushout f c.inl iY fE
s : BinaryCofan ((pair X E).obj { as := WalkingPair.right }) Y
m : YE ⟶ s.pt
e₁ : (c.inr ≫ fE) ≫ m = s.inl
e₂ : iY ≫ m = s.inr
⊢ H.cocone.inr ≫ m =
    H.cocone.inr ≫ H.isColimit.desc (PushoutCocone.mk s.inr (hc.desc (BinaryCofan.mk (f ≫ s.inr) s.inl)) ⋯)

Tactic:
rw [H.isColimit.fac _ WalkingSpan.right]

Result:
case mpr.uniq.h₁
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H✝ : CommSq f c.inl iY fE
H : IsPushout f c.inl iY fE
s : BinaryCofan ((pair X E).obj { as := WalkingPair.right }) Y
m : YE ⟶ s.pt
e₁ : (c.inr ≫ fE) ≫ m = s.inl
e₂ : iY ≫ m = s.inr
⊢ H.cocone.inr ≫ m = (PushoutCocone.mk s.inr (hc.desc (BinaryCofan.mk (f ≫ s.inr) s.inl)) ⋯).ι.app WalkingSpan.right

Proof state:
case mp.intro.refine_2
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
⊢ ∀ {m : YE ⟶ s.pt},
    PushoutCocone.inl
            { pt := YE,
              ι := { app := fun j => Option.rec (f ≫ iY) (fun val => WalkingPair.rec iY fE val) j, naturality := ⋯ } } ≫
          m =
        s.inl →
      fE ≫ m = s.ι.app WalkingSpan.right → m = h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl)

Tactic:
intro m e₁ e₂

Result:
case mp.intro.refine_2
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
m : YE ⟶ s.pt
e₁ :
  PushoutCocone.inl
        { pt := YE,
          ι := { app := fun j => Option.rec (f ≫ iY) (fun val => WalkingPair.rec iY fE val) j, naturality := ⋯ } } ≫
      m =
    s.inl
e₂ : fE ≫ m = s.ι.app WalkingSpan.right
⊢ m = h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl)

Proof state:
case mpr.desc
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H✝ : CommSq f c.inl iY fE
H : IsPushout f c.inl iY fE
⊢ (s : BinaryCofan ((pair X E).obj { as := WalkingPair.right }) Y) → YE ⟶ s.pt

Tactic:
exact fun s => H.isColimit.desc (PushoutCocone.mk s.inr _ <|
  (hc.fac (BinaryCofan.mk (f ≫ s.inr) s.inl) ⟨WalkingPair.left⟩).symm)

Result:
no goals

Proof state:
case mpr.uniq.h₁.h₂
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H✝ : CommSq f c.inl iY fE
H : IsPushout f c.inl iY fE
s : BinaryCofan ((pair X E).obj { as := WalkingPair.right }) Y
m : YE ⟶ s.pt
e₁ : (c.inr ≫ fE) ≫ m = s.inl
e₂ : iY ≫ m = s.inr
⊢ c.inr ≫ (PushoutCocone.mk s.inr (hc.desc (BinaryCofan.mk (f ≫ s.inr) s.inl)) ⋯).ι.app WalkingSpan.right = s.inl

Tactic:
exact hc.fac _ _

Result:
no goals

Proof state:
case mp.intro.refine_2
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
m : YE ⟶ s.pt
e₁ :
  PushoutCocone.inl
        { pt := YE,
          ι := { app := fun j => Option.rec (f ≫ iY) (fun val => WalkingPair.rec iY fE val) j, naturality := ⋯ } } ≫
      m =
    s.inl
e₂ : fE ≫ m = s.ι.app WalkingSpan.right
⊢ m = h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl)

Tactic:
apply BinaryCofan.IsColimit.hom_ext h

Result:
case mp.intro.refine_2.h₁
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
m : YE ⟶ s.pt
e₁ :
  PushoutCocone.inl
        { pt := YE,
          ι := { app := fun j => Option.rec (f ≫ iY) (fun val => WalkingPair.rec iY fE val) j, naturality := ⋯ } } ≫
      m =
    s.inl
e₂ : fE ≫ m = s.ι.app WalkingSpan.right
⊢ (BinaryCofan.mk (c.inr ≫ fE) iY).inl ≫ m =
    (BinaryCofan.mk (c.inr ≫ fE) iY).inl ≫ h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl)

case mp.intro.refine_2.h₂
C : Type u
inst✝ : Category.{v, u} C
X E Y YE : C
c : BinaryCofan X E
hc : IsColimit c
f : X ⟶ Y
iY : Y ⟶ YE
fE : c.pt ⟶ YE
H : CommSq f c.inl iY fE
h : IsColimit (BinaryCofan.mk (c.inr ≫ fE) iY)
s : PushoutCocone f c.inl
m : YE ⟶ s.pt
e₁ :
  PushoutCocone.inl
        { pt := YE,
          ι := { app := fun j => Option.rec (f ≫ iY) (fun val => WalkingPair.rec iY fE val) j, naturality := ⋯ } } ≫
      m =
    s.inl
e₂ : fE ≫ m = s.ι.app WalkingSpan.right
⊢ (BinaryCofan.mk (c.inr ≫ fE) iY).inr ≫ m =
    (BinaryCofan.mk (c.inr ≫ fE) iY).inr ≫ h.desc (BinaryCofan.mk (c.inr ≫ s.inr) s.inl)