@@ -726,4 +726,141 @@ theorem echo_roundtrip_typed (e : Expr) (n : Nat) (h : HasType [] e (.word n)) :
726726 HasType [] (.lower (.echoClose e)) (.word 0 ) :=
727727 ⟨.tResidue _ _ _ _ (.tEchoClose _ _ n h), .tLower _ _ _ _ (.tEchoClose _ _ n h)⟩
728728
729+ -- ═══════════════════════════════════════════════════════════════════════
730+ -- TG-2: DECIDABILITY OF TYPE CHECKING
731+ -- ═══════════════════════════════════════════════════════════════════════
732+ --
733+ -- `infer Γ e` computes the unique type of `e` in context `Γ`, or `none` if `e`
734+ -- is ill-typed. It is the algorithmic counterpart of the `HasType` relation:
735+ -- `infer_sound` + `infer_complete` prove the two equivalent, hence `HasType`
736+ -- is decidable (`decidableHasType`) and types are unique (`type_unique`).
737+ -- This is the specification `compiler/lib/typecheck.ml` is meant to refine
738+ -- (TG-3).
739+
740+ /-- Algorithmic type inference: total, structurally recursive on the AST. -/
741+ def infer (Γ : Ctx) : Expr → Option Ty
742+ | .num _ => some .num
743+ | .str _ => some .str
744+ | .boolLit _ => some .bool
745+ | .identity => some (.word 0 )
746+ | .braidLit gs => some (.word (generatorWidth gs))
747+ | .compose e₁ e₂ =>
748+ match infer Γ e₁, infer Γ e₂ with
749+ | some (.word n), some (.word m) => some (.word (max n m))
750+ | _, _ => none
751+ | .tensor e₁ e₂ =>
752+ match infer Γ e₁, infer Γ e₂ with
753+ | some (.word n), some (.word m) => some (.word (n + m))
754+ | _, _ => none
755+ | .pipeline e₁ e₂ =>
756+ match infer Γ e₁, infer Γ e₂ with
757+ | some (.word n), some (.word m) => some (.word (max n m))
758+ | _, _ => none
759+ | .close e =>
760+ match infer Γ e with
761+ | some (.word _) => some (.word 0 )
762+ | _ => none
763+ | .add e₁ e₂ =>
764+ match infer Γ e₁, infer Γ e₂ with
765+ | some .num, some .num => some .num
766+ | _, _ => none
767+ | .eq e₁ e₂ =>
768+ match infer Γ e₁, infer Γ e₂ with
769+ | some (.word n), some (.word m) => if n = m then some .bool else none
770+ | some .num, some .num => some .bool
771+ | some .str, some .str => some .bool
772+ | _, _ => none
773+ | .echoClose e =>
774+ match infer Γ e with
775+ | some (.word n) => some (.echo (.word n) (.word 0 ))
776+ | _ => none
777+ | .lower e =>
778+ match infer Γ e with
779+ | some (.echo _ τ) => some τ
780+ | _ => none
781+ | .residue e =>
782+ match infer Γ e with
783+ | some (.echo ρ _) => some ρ
784+ | _ => none
785+
786+ /-- **Completeness** : every typing derivation is computed by `infer`. -/
787+ theorem infer_complete {Γ : Ctx} {e : Expr} {τ : Ty} :
788+ HasType Γ e τ → infer Γ e = some τ := by
789+ intro h
790+ induction h <;> simp_all [infer]
791+
792+ /-- **Soundness** : every successful inference is a valid typing derivation. -/
793+ theorem infer_sound {Γ : Ctx} {e : Expr} {τ : Ty} :
794+ infer Γ e = some τ → HasType Γ e τ := by
795+ induction e generalizing Γ τ with
796+ | num _ => intro h; simp only [infer, Option.some.injEq] at h; subst h; exact .tNum _ _
797+ | str _ => intro h; simp only [infer, Option.some.injEq] at h; subst h; exact .tStr _ _
798+ | boolLit _ => intro h; simp only [infer, Option.some.injEq] at h; subst h; exact .tBool _ _
799+ | identity => intro h; simp only [infer, Option.some.injEq] at h; subst h; exact .tIdentity _
800+ | braidLit _ => intro h; simp only [infer, Option.some.injEq] at h; subst h; exact .tBraid _ _
801+ | compose e₁ e₂ ih₁ ih₂ =>
802+ intro h; simp only [infer] at h; split at h
803+ next n m he₁ he₂ =>
804+ injection h with h; subst h; exact .tComposeWord _ _ _ n m (ih₁ he₁) (ih₂ he₂)
805+ all_goals simp at h
806+ | tensor e₁ e₂ ih₁ ih₂ =>
807+ intro h; simp only [infer] at h; split at h
808+ next n m he₁ he₂ =>
809+ injection h with h; subst h; exact .tTensorWord _ _ _ n m (ih₁ he₁) (ih₂ he₂)
810+ all_goals simp at h
811+ | pipeline e₁ e₂ ih₁ ih₂ =>
812+ intro h; simp only [infer] at h; split at h
813+ next n m he₁ he₂ =>
814+ injection h with h; subst h
815+ exact .tPipeline _ _ _ _ (.tComposeWord _ _ _ n m (ih₁ he₁) (ih₂ he₂))
816+ all_goals simp at h
817+ | close e ih =>
818+ intro h; simp only [infer] at h; split at h
819+ next k he => injection h with h; subst h; exact .tCloseWord _ _ k (ih he)
820+ all_goals simp at h
821+ | add e₁ e₂ ih₁ ih₂ =>
822+ intro h; simp only [infer] at h; split at h
823+ next he₁ he₂ => injection h with h; subst h; exact .tAddNum _ _ _ (ih₁ he₁) (ih₂ he₂)
824+ all_goals simp at h
825+ | eq e₁ e₂ ih₁ ih₂ =>
826+ intro h; simp only [infer] at h; split at h
827+ next n m he₁ he₂ =>
828+ split at h
829+ next hnm =>
830+ injection h with h; subst h; subst hnm
831+ exact .tEqWord _ _ _ _ (ih₁ he₁) (ih₂ he₂)
832+ next => simp at h
833+ next he₁ he₂ => injection h with h; subst h; exact .tEqNum _ _ _ (ih₁ he₁) (ih₂ he₂)
834+ next he₁ he₂ => injection h with h; subst h; exact .tEqStr _ _ _ (ih₁ he₁) (ih₂ he₂)
835+ all_goals simp at h
836+ | echoClose e ih =>
837+ intro h; simp only [infer] at h; split at h
838+ next k he => injection h with h; subst h; exact .tEchoClose _ _ k (ih he)
839+ all_goals simp at h
840+ | lower e ih =>
841+ intro h; simp only [infer] at h; split at h
842+ next ρ τ' he => injection h with h; subst h; exact .tLower _ _ ρ τ' (ih he)
843+ all_goals simp at h
844+ | residue e ih =>
845+ intro h; simp only [infer] at h; split at h
846+ next ρ τ' he => injection h with h; subst h; exact .tResidue _ _ ρ τ' (ih he)
847+ all_goals simp at h
848+
849+ /-- **Decidability of type checking** (TG-2): `infer` decides `HasType`. -/
850+ theorem infer_iff_hasType {Γ : Ctx} {e : Expr} {τ : Ty} :
851+ infer Γ e = some τ ↔ HasType Γ e τ :=
852+ ⟨infer_sound, infer_complete⟩
853+
854+ /-- Types are unique: `HasType` assigns at most one type per (context, term). -/
855+ theorem type_unique {Γ : Ctx} {e : Expr} {τ₁ τ₂ : Ty}
856+ (h₁ : HasType Γ e τ₁) (h₂ : HasType Γ e τ₂) : τ₁ = τ₂ := by
857+ have p₁ := infer_complete h₁
858+ have p₂ := infer_complete h₂
859+ rw [p₁] at p₂
860+ exact Option.some.inj p₂
861+
862+ /-- Type checking in the empty context is decidable. -/
863+ instance decidableHasType (e : Expr) (τ : Ty) : Decidable (HasType [] e τ) :=
864+ decidable_of_iff (infer [] e = some τ) infer_iff_hasType
865+
729866end Tangle
0 commit comments