val congruence_fun (#a: _) (#b: (a -> Type)) (f g: (x: a -> b x)) (x: squash (forall x. f x == g x))
    : Lemma (ensures (fun (x: a) -> f x) == (fun (x: a) -> g x))
val congruence_fun (#a: _) (#b: (a -> Type)) (f g: (x: a -> b x)) (x: squash (forall x. f x == g x))
    : Lemma (ensures (fun (x: a) -> f x) == (fun (x: a) -> g x))
let congruence_fun #a (#b:a -> Type) (f g:(x:a -> b x)) (x:squash (forall x. f x == g x)) :
  Lemma (ensures (fun (x:a) -> f x) == (fun (x:a) -> g x)) =
  assert ((fun (x:a) -> f x) == (fun (x:a) -> g x))
      by (l_to_r [quote (q_as_lem x)];
          trefl())
(*
   Copyright 2008-2018 Microsoft Research

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*)
module Postprocess

open FStar.Tactics.V2

assume val foo : int -> int
assume val lem : unit -> Lemma (foo 1 == foo 2)
let tau () = apply_lemma (`lem)

[@@(postprocess_with tau)]
let x : int = foo 1

[@@(postprocess_for_extraction_with tau)]
let y : int = foo 1

let _ = assert (x == foo 2)
let _ = assert (y == foo 1) // but `foo 2` in extracted code

(* More hardcore transformations *)

noeq
type t1 =
    | A1 : t1
    | B1 : int -> t1
    | C1 : (int -> t1) -> t1

noeq
type t2 =
    | A2 : t2
    | B2 : int -> t2
    | C2 : (int -> t2) -> t2

let rec lift : t1 -> t2 =
    function
    | A1 -> A2
    | B1 i -> B2 i
    | C1 f -> C2 (fun x -> lift (f x))

let lemA () : Lemma (lift A1 == A2) = ()
let lemB x : Lemma (lift (B1 x) == (B2 x)) = ()
let lemC ($f: int -> t1) : Lemma (lift (C1 f) == C2 (fun x -> lift (f x))) by (compute ()) = ()

(* These could really be polymorphic *)
let congB #i #j (_ : squash (i == j)) : Lemma (B2 i == B2 j) = ()
let congC #f #g (_ : squash (f == g)) : Lemma (C2 f == C2 g) = ()

let xx = C1 (function
             | 0 -> A1
             | 5 -> B1 42
             | x -> B1 24)

open FStar.FunctionalExtensionality

let q_as_lem (#a:Type) (#b:a -> Type) (p:squash (forall x. b x)) (x:a)
  : Lemma (b x)
  = ()
/
prims.fst.checked FStar.Tactics.V2.fst.checked FStar.Tactics.Effect.fsti.checked FStar.Pervasives.fsti.checked FStar.FunctionalExtensionality.fsti.checked
Postprocess.fst
f: (x: a -> b x) -> g: (x: a -> b x) -> x: Prims.squash (forall (x: a). f x == g x)
  -> FStar.Pervasives.Lemma (ensures (fun x -> f x) == (fun x -> g x))
Prims.squash Prims.l_Forall Prims.eq2 FStar.Tactics.Effect.assert_by_tactic Prims.unit FStar.Tactics.V2.Derived.trefl FStar.Tactics.V2.Derived.l_to_r Prims.list FStar.Tactics.NamedView.term Prims.Cons Prims.Nil Postprocess.q_as_lem FStar.Stubs.Reflection.Types.term Prims.l_True FStar.Pervasives.pattern
let congruence_fun
      #a
      (#b: (a -> Type))
      (f: (x: a -> b x))
      (g: (x: a -> b x))
      (x: squash (forall x. f x == g x))
    : Lemma (ensures (fun (x: a) -> f x) == (fun (x: a) -> g x)) =
  
FStar.Tactics.Effect.assert_by_tactic ((fun (x: a) -> f x) == (fun (x: a) -> g x))
  (fun _ ->
      ();
      (l_to_r [quote (q_as_lem x)];
        trefl ()))