jaccokrijnen / plutus-cert

0 stars 2 forks source link

Shadowing of type variables is problematic in static semantics #16

Open jaccokrijnen opened 1 year ago

jaccokrijnen commented 1 year ago

Consider this term

const x y = x

Implemented in PIR like this:

(Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x)

Apply this to arguments:

  (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) String "foo" Bool True

it should have type String

However, the inner derivation looks like

  --------------------------------------- T-Var
  [α : * , α : *] ; [y: α, x : α] ⊢ x : α
  ----------------------------------------------
  [α : * , α : *] ; [x : α] ⊢ λ(y : α) . x : α -> α
  ----------------------------------------------
  [α : *] ; [x : α] ⊢ Λα. λ(y : α). x : ∀α. α -> α
  ----------------------------------------------------
                      ... 
  --------------------------------------------------------------------
    ⊢ (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) : ∀α. (α -> (∀α. α -> α))          !!! this type is wrong, the rightmost α refers to the shadowed α
  --------------------------------------------------------------------------
    ⊢ (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) String : (String -> (∀α. α -> α))
  --------------------------------------------------------------------------
    ⊢ (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) String "foo" Bool : Bool -> Bool
  --------------------------------------------------------------------------
    ⊢ (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) String "foo" Bool True : Bool
jaccokrijnen commented 1 year ago

Ilya Sergey mentioned they had found a similar problem in the type checker of Scilla: https://icfp22.sigplan.org/details/icfp-2022-papers/33/Random-Testing-of-a-Higher-Order-Blockchain-Language

jaccokrijnen commented 1 year ago

This must be solved before, it's regular system F anyways.

jaccokrijnen commented 1 year ago

Possible solutions

jaccokrijnen commented 1 year ago

I was writing a small proof of concept in Coq to demonstrate the problem

WIP:

From PlutusCert Require Import
  PlutusIR
  Static.
Import NamedTerm.
From Coq Require Import
  Strings.String.

Local Open Scope string_scope.
Definition t := TyAbs "α" Kind_Base (LamAbs "x" (Ty_Var "α") (TyAbs "α" Kind_Base (Var "x"))).
Definition t_ty :=
  Ty_Forall "α" Kind_Base (
    Ty_Fun
      (Ty_Var "α")
      (Ty_Forall "α" Kind_Base
        (Ty_Var "α")
      )
  ).

Lemma t_typing : empty,, empty |-+ t : t_ty.
Proof.
  unfold t, t_ty.
  apply T_TyAbs.
  apply T_LamAbs.
    - eauto with typing.
    - eauto with typing.
    - apply T_TyAbs.
      eapply T_Var.
      + cbn. reflexivity.
      + eauto with typing.
Qed.

Definition Ty_int : Ty := Ty_Builtin (Some (TypeIn DefaultUniInteger)).
Definition Ty_bool : Ty := Ty_Builtin (Some (TypeIn DefaultUniBool)).
Definition t_true : Term := Constant (Some (ValueOf DefaultUniBool true)).

Definition t' := TyInst (Apply (TyInst t Ty_bool) (t_true)) (Ty_int).

Lemma t'_typing : empty,, empty |-+ t' : Ty_int.
Proof with eauto with typing.
  unfold t'.
  eapply T_TyInst...
  - eapply T_Apply...
    eapply T_TyInst...
    + apply t_typing...
    + apply N_TyBuiltin.
    + simpl.
jaccokrijnen commented 1 year ago

I now wonder what type preservation theorem would look like, because then we could prove "foo" : Bool by reducing this program:

  (Λ(α : *) λ(x : α) Λ(α : *) λ(y : α). x) String "foo" Bool True

TODO: figure out if there is a type preservation/subject reduction proof in Joris' work, and if that makes any assumptions to avoid this case.

Perhaps it uses this axiom: