src/HOL/Tools/SMT/smt_translate.ML
changeset 41281 679118e35378
parent 41250 41f86829e22f
child 41328 6792a5c92a58
equal deleted inserted replaced
41280:a7de9d36f4f2 41281:679118e35378
   118   header = header,
   118   header = header,
   119   sorts = Typtab.fold (fn (_, (n, true)) => cons n | _ => I) typs [],
   119   sorts = Typtab.fold (fn (_, (n, true)) => cons n | _ => I) typs [],
   120   dtyps = dtyps,
   120   dtyps = dtyps,
   121   funcs = Termtab.fold (fn (_, (n, SOME ss)) => cons (n,ss) | _ => I) terms []}
   121   funcs = Termtab.fold (fn (_, (n, SOME ss)) => cons (n,ss) | _ => I) terms []}
   122 
   122 
   123 fun recon_of ctxt rules thms ithms revertT revert (_, _, typs, _, _, terms) =
   123 fun recon_of ctxt rules thms ithms (_, _, typs, _, _, terms) =
   124   let
   124   let
   125     fun add_typ (T, (n, _)) = Symtab.update (n, revertT T)
   125     fun add_typ (T, (n, _)) = Symtab.update (n, T)
   126     val typs' = Typtab.fold add_typ typs Symtab.empty
   126     val typs' = Typtab.fold add_typ typs Symtab.empty
   127 
   127 
   128     fun add_fun (t, (n, _)) = Symtab.update (n, revert t)
   128     fun add_fun (t, (n, _)) = Symtab.update (n, t)
   129     val terms' = Termtab.fold add_fun terms Symtab.empty
   129     val terms' = Termtab.fold add_fun terms Symtab.empty
   130 
   130 
   131     val assms = map (pair ~1) thms @ ithms
   131     val assms = map (pair ~1) thms @ ithms
   132   in
   132   in
   133     {context=ctxt, typs=typs', terms=terms', rewrite_rules=rules, assms=assms}
   133     {context=ctxt, typs=typs', terms=terms', rewrite_rules=rules, assms=assms}
   135 
   135 
   136 
   136 
   137 
   137 
   138 (* preprocessing *)
   138 (* preprocessing *)
   139 
   139 
   140 (** mark built-in constants as Var **)
       
   141 
       
   142 fun mark_builtins ctxt =
       
   143   let
       
   144     (*
       
   145       Note: schematic terms cannot occur anymore in terms at this stage.
       
   146     *)
       
   147     fun mark t =
       
   148       (case Term.strip_comb t of
       
   149         (u as Const (@{const_name If}, _), ts) => marks u ts
       
   150       | (u as @{const SMT.weight}, [t1, t2]) =>
       
   151           mark t2 #>> (fn t2' => u $ t1 $ t2')
       
   152       | (u as Const c, ts) =>
       
   153           (case B.builtin_num ctxt t of
       
   154             SOME (n, T) =>
       
   155               let val v = ((n, 0), T)
       
   156               in Vartab.update v #> pair (Var v) end
       
   157           | NONE =>
       
   158               (case B.builtin_fun ctxt c ts of
       
   159                 SOME ((ni, T), us, U) =>
       
   160                   Vartab.update (ni, U) #> marks (Var (ni, T)) us
       
   161               | NONE => marks u ts))
       
   162       | (Abs (n, T, u), ts) => mark u #-> (fn u' => marks (Abs (n, T, u')) ts)
       
   163       | (u, ts) => marks u ts)
       
   164  
       
   165     and marks t ts = fold_map mark ts #>> Term.list_comb o pair t
       
   166 
       
   167   in (fn ts => swap (fold_map mark ts Vartab.empty)) end
       
   168 
       
   169 fun mark_builtins' ctxt t = hd (snd (mark_builtins ctxt [t]))
       
   170 
       
   171 
       
   172 (** FIXME **)
   140 (** FIXME **)
   173 
   141 
   174 local
   142 local
   175   (*
   143   (*
   176     mark constructors and selectors as Vars (forcing eta-expansion),
   144     force eta-expansion for constructors and selectors,
   177     add missing datatype selectors via hypothetical definitions,
   145     add missing datatype selectors via hypothetical definitions,
   178     also return necessary datatype and record theorems
   146     also return necessary datatype and record theorems
   179   *)
   147   *)
   180 in
   148 in
   181 
   149 
   198 
   166 
   199   fun exp2' T l =
   167   fun exp2' T l =
   200     let val (U1, U2) = Term.dest_funT T ||> Term.domain_type
   168     let val (U1, U2) = Term.dest_funT T ||> Term.domain_type
   201     in Abs (Name.uu, U1, eta U2 (l $ Bound 0)) end
   169     in Abs (Name.uu, U1, eta U2 (l $ Bound 0)) end
   202 
   170 
   203   fun expf t i T ts =
   171   fun expf k i T t =
   204     let val Ts = U.dest_funT i T |> fst |> drop (length ts)
   172     let val Ts = drop i (fst (U.dest_funT k T))
   205     in
   173     in
   206       Term.list_comb (t, ts)
   174       Term.incr_boundvars (length Ts) t
   207       |> Term.incr_boundvars (length Ts)
       
   208       |> fold_index (fn (i, _) => fn u => u $ Bound i) Ts
   175       |> fold_index (fn (i, _) => fn u => u $ Bound i) Ts
   209       |> fold_rev (fn T => fn u => Abs (Name.uu, T, u)) Ts
   176       |> fold_rev (fn T => fn u => Abs (Name.uu, T, u)) Ts
   210     end
   177     end
   211 
       
   212   fun expand ((q as Const (@{const_name All}, _)) $ Abs a) = q $ abs_expand a
       
   213     | expand ((q as Const (@{const_name All}, T)) $ t) = q $ exp T t
       
   214     | expand (q as Const (@{const_name All}, T)) = exp2 T q
       
   215     | expand ((q as Const (@{const_name Ex}, _)) $ Abs a) = q $ abs_expand a
       
   216     | expand ((q as Const (@{const_name Ex}, T)) $ t) = q $ exp T t
       
   217     | expand (q as Const (@{const_name Ex}, T)) = exp2 T q
       
   218     | expand ((l as Const (@{const_name Let}, _)) $ t $ Abs a) =
       
   219         l $ expand t $ abs_expand a
       
   220     | expand ((l as Const (@{const_name Let}, T)) $ t $ u) =
       
   221         l $ expand t $ exp (Term.range_type T) u
       
   222     | expand ((l as Const (@{const_name Let}, T)) $ t) = exp2 T (l $ expand t)
       
   223     | expand (l as Const (@{const_name Let}, T)) = exp2' T l
       
   224     | expand (Abs a) = abs_expand a
       
   225     | expand t =
       
   226         (case Term.strip_comb t of
       
   227           (u as Const (@{const_name If}, T), ts) => expf u 3 T (map expand ts)
       
   228         | (u as Var ((_, i), T), ts) => expf u i T (map expand ts)
       
   229         | (u, ts) => Term.list_comb (u, map expand ts))
       
   230 
       
   231   and abs_expand (n, T, t) = Abs (n, T, expand t)
       
   232 in
   178 in
   233 
   179 
   234 val eta_expand = map expand
   180 fun eta_expand ctxt =
       
   181   let
       
   182     fun expand ((q as Const (@{const_name All}, _)) $ Abs a) = q $ abs_expand a
       
   183       | expand ((q as Const (@{const_name All}, T)) $ t) = q $ exp T t
       
   184       | expand (q as Const (@{const_name All}, T)) = exp2 T q
       
   185       | expand ((q as Const (@{const_name Ex}, _)) $ Abs a) = q $ abs_expand a
       
   186       | expand ((q as Const (@{const_name Ex}, T)) $ t) = q $ exp T t
       
   187       | expand (q as Const (@{const_name Ex}, T)) = exp2 T q
       
   188       | expand ((l as Const (@{const_name Let}, _)) $ t $ Abs a) =
       
   189           l $ expand t $ abs_expand a
       
   190       | expand ((l as Const (@{const_name Let}, T)) $ t $ u) =
       
   191           l $ expand t $ exp (Term.range_type T) u
       
   192       | expand ((l as Const (@{const_name Let}, T)) $ t) =
       
   193           exp2 T (l $ expand t)
       
   194       | expand (l as Const (@{const_name Let}, T)) = exp2' T l
       
   195       | expand t =
       
   196           (case Term.strip_comb t of
       
   197             (u as Const (c as (_, T)), ts) =>
       
   198               (case B.dest_builtin ctxt c ts of
       
   199                 SOME (_, k, us, mk) =>
       
   200                   if k = length us then mk (map expand us)
       
   201                   else expf k (length ts) T (mk (map expand us))
       
   202               | NONE => Term.list_comb (u, map expand ts))
       
   203           | (Abs a, ts) => Term.list_comb (abs_expand a, map expand ts)
       
   204           | (u, ts) => Term.list_comb (u, map expand ts))
       
   205 
       
   206     and abs_expand (n, T, t) = Abs (n, T, expand t)
       
   207   
       
   208   in map expand end
   235 
   209 
   236 end
   210 end
   237 
   211 
   238 
   212 
   239 (** lambda-lifting **)
   213 (** lambda-lifting **)
   352 end
   326 end
   353 
   327 
   354 
   328 
   355 (** map HOL formulas to FOL formulas (i.e., separate formulas froms terms) **)
   329 (** map HOL formulas to FOL formulas (i.e., separate formulas froms terms) **)
   356 
   330 
   357 val tboolT = @{typ SMT.term_bool}
   331 local
   358 val term_true = Const (@{const_name True}, tboolT)
   332   val term_bool = @{lemma "SMT.term_true ~= SMT.term_false"
   359 val term_false = Const (@{const_name False}, tboolT)
   333     by (simp add: SMT.term_true_def SMT.term_false_def)}
   360 
   334 
   361 val term_bool = @{lemma "True ~= False" by simp}
   335   val fol_rules = [
   362 val term_bool_prop =
   336     Let_def,
   363   let
   337     mk_meta_eq @{thm SMT.term_true_def},
   364     fun replace @{const HOL.eq (bool)} = @{const HOL.eq (SMT.term_bool)}
   338     mk_meta_eq @{thm SMT.term_false_def},
   365       | replace @{const True} = term_true
   339     @{lemma "P = True == P" by (rule eq_reflection) simp},
   366       | replace @{const False} = term_false
   340     @{lemma "if P then True else False == P" by (rule eq_reflection) simp}]
   367       | replace t = t
   341 
   368   in Term.map_aterms replace (U.prop_of term_bool) end
   342   fun reduce_let (Const (@{const_name Let}, _) $ t $ u) =
   369 
   343         reduce_let (Term.betapply (u, t))
   370 val fol_rules = [
   344     | reduce_let (t $ u) = reduce_let t $ reduce_let u
   371   Let_def,
   345     | reduce_let (Abs (n, T, t)) = Abs (n, T, reduce_let t)
   372   @{lemma "P = True == P" by (rule eq_reflection) simp},
   346     | reduce_let t = t
   373   @{lemma "if P then True else False == P" by (rule eq_reflection) simp}]
   347 
   374 
   348   fun as_term t = @{const HOL.eq (bool)} $ t $ @{const SMT.term_true}
   375 fun reduce_let (Const (@{const_name Let}, _) $ t $ u) =
   349 
   376       reduce_let (Term.betapply (u, t))
   350   fun wrap_in_if t =
   377   | reduce_let (t $ u) = reduce_let t $ reduce_let u
   351     @{const If (bool)} $ t $ @{const SMT.term_true} $ @{const SMT.term_false}
   378   | reduce_let (Abs (n, T, t)) = Abs (n, T, reduce_let t)
   352 
   379   | reduce_let t = t
   353   fun is_builtin_conn_or_pred ctxt c ts =
   380 
   354     is_some (B.dest_builtin_conn ctxt c ts) orelse
   381 fun is_pred_type NONE = false
   355     is_some (B.dest_builtin_pred ctxt c ts)
   382   | is_pred_type (SOME T) = (Term.body_type T = @{typ bool})
   356 
   383 
   357   fun builtin b ctxt c ts =
   384 fun is_conn_type NONE = false
   358     (case (Const c, ts) of
   385   | is_conn_type (SOME T) =
   359       (@{const HOL.eq (bool)}, [t, u]) =>
   386       forall (equal @{typ bool}) (Term.body_type T :: Term.binder_types T)
   360         if t = @{const SMT.term_true} orelse u = @{const SMT.term_true} then
   387 
   361           B.dest_builtin_eq ctxt t u
   388 fun revert_typ @{typ SMT.term_bool} = @{typ bool}
   362         else b ctxt c ts
   389   | revert_typ (Type (n, Ts)) = Type (n, map revert_typ Ts)
   363     | _ => b ctxt c ts)
   390   | revert_typ T = T
   364 in
   391 
   365 
   392 val revert_types = Term.map_types revert_typ
   366 fun folify ctxt =
   393 
   367   let
   394 fun folify ctxt builtins =
       
   395   let
       
   396     fun as_term t = @{const HOL.eq (SMT.term_bool)} $ t $ term_true
       
   397 
       
   398     fun as_tbool @{typ bool} = tboolT
       
   399       | as_tbool (Type (n, Ts)) = Type (n, map as_tbool Ts)
       
   400       | as_tbool T = T
       
   401     fun mapTs f g i = U.dest_funT i #> (fn (Ts, T) => map f Ts ---> g T)
       
   402     fun predT i = mapTs as_tbool I i
       
   403     fun funcT i = mapTs as_tbool as_tbool i
       
   404     fun func i (n, T) = (n, funcT i T)
       
   405 
       
   406     fun map_ifT T = T |> Term.dest_funT ||> funcT 2 |> (op -->)
       
   407     val if_term = @{const If (bool)} |> Term.dest_Const ||> map_ifT |> Const
       
   408     fun wrap_in_if t = if_term $ t $ term_true $ term_false
       
   409 
       
   410     fun in_list T f t = HOLogic.mk_list T (map f (HOLogic.dest_list t))
   368     fun in_list T f t = HOLogic.mk_list T (map f (HOLogic.dest_list t))
   411 
   369 
   412     fun in_term t =
   370     fun in_term t =
   413       (case Term.strip_comb t of
   371       (case Term.strip_comb t of
   414         (Const (n as @{const_name If}, T), [t1, t2, t3]) =>
   372         (@{const True}, []) => @{const SMT.term_true}
   415           Const (n, map_ifT T) $ in_form t1 $ in_term t2 $ in_term t3
   373       | (@{const False}, []) => @{const SMT.term_false}
   416       | (Const (@{const_name HOL.eq}, _), _) => wrap_in_if (in_form t)
   374       | (u as Const (@{const_name If}, _), [t1, t2, t3]) =>
   417       | (Var (ni as (_, i), T), ts) =>
   375           u $ in_form t1 $ in_term t2 $ in_term t3
   418           let val U = Vartab.lookup builtins ni
       
   419           in
       
   420             if is_conn_type U orelse is_pred_type U then wrap_in_if (in_form t)
       
   421             else Term.list_comb (Var (ni, funcT i T), map in_term ts)
       
   422           end
       
   423       | (Const c, ts) =>
   376       | (Const c, ts) =>
   424           Term.list_comb (Const (func (length ts) c), map in_term ts)
   377           if is_builtin_conn_or_pred ctxt c ts then wrap_in_if (in_form t)
   425       | (Free c, ts) =>
   378           else Term.list_comb (Const c, map in_term ts)
   426           Term.list_comb (Free (func (length ts) c), map in_term ts)
   379       | (Free c, ts) => Term.list_comb (Free c, map in_term ts)
   427       | _ => t)
   380       | _ => t)
   428 
   381 
   429     and in_weight ((c as @{const SMT.weight}) $ w $ t) = c $ w $ in_form t
   382     and in_weight ((c as @{const SMT.weight}) $ w $ t) = c $ w $ in_form t
   430       | in_weight t = in_form t 
   383       | in_weight t = in_form t 
   431 
   384 
   432     and in_pat (Const (c as (@{const_name SMT.pat}, _)) $ t) =
   385     and in_pat ((p as Const (@{const_name SMT.pat}, _)) $ t) = p $ in_term t
   433           Const (func 1 c) $ in_term t
   386       | in_pat ((p as Const (@{const_name SMT.nopat}, _)) $ t) = p $ in_term t
   434       | in_pat (Const (c as (@{const_name SMT.nopat}, _)) $ t) =
       
   435           Const (func 1 c) $ in_term t
       
   436       | in_pat t = raise TERM ("bad pattern", [t])
   387       | in_pat t = raise TERM ("bad pattern", [t])
   437 
   388 
   438     and in_pats ps =
   389     and in_pats ps =
   439       in_list @{typ "SMT.pattern list"} (in_list @{typ SMT.pattern} in_pat) ps
   390       in_list @{typ "SMT.pattern list"} (in_list @{typ SMT.pattern} in_pat) ps
   440 
   391 
   441     and in_trig ((c as @{const SMT.trigger}) $ p $ t) =
   392     and in_trigger ((c as @{const SMT.trigger}) $ p $ t) =
   442           c $ in_pats p $ in_weight t
   393           c $ in_pats p $ in_weight t
   443       | in_trig t = in_weight t
   394       | in_trigger t = in_weight t
   444 
   395 
   445     and in_form t =
   396     and in_form t =
   446       (case Term.strip_comb t of
   397       (case Term.strip_comb t of
   447         (q as Const (qn, _), [Abs (n, T, u)]) =>
   398         (q as Const (qn, _), [Abs (n, T, u)]) =>
   448           if member (op =) [@{const_name All}, @{const_name Ex}] qn then
   399           if member (op =) [@{const_name All}, @{const_name Ex}] qn then
   449             q $ Abs (n, as_tbool T, in_trig u)
   400             q $ Abs (n, T, in_trigger u)
   450           else as_term (in_term t)
   401           else as_term (in_term t)
   451       | (u as Const (@{const_name If}, _), ts) =>
   402       | (Const c, ts) =>
   452           Term.list_comb (u, map in_form ts)
   403           (case B.dest_builtin_conn ctxt c ts of
   453       | (b as @{const HOL.eq (bool)}, ts) => Term.list_comb (b, map in_form ts)
   404             SOME (_, _, us, mk) => mk (map in_form us)
   454       | (Const (n as @{const_name HOL.eq}, T), ts) =>
   405           | NONE =>
   455           Term.list_comb (Const (n, predT 2 T), map in_term ts)
   406               (case B.dest_builtin_pred ctxt c ts of
   456       | (b as Var (ni as (_, i), T), ts) =>
   407                 SOME (_, _, us, mk) => mk (map in_term us)
   457           if is_conn_type (Vartab.lookup builtins ni) then
   408               | NONE => as_term (in_term t)))
   458             Term.list_comb (b, map in_form ts)
       
   459           else if is_pred_type (Vartab.lookup builtins ni) then
       
   460             Term.list_comb (Var (ni, predT i T), map in_term ts)
       
   461           else as_term (in_term t)
       
   462       | _ => as_term (in_term t))
   409       | _ => as_term (in_term t))
   463   in
   410   in
   464     map (reduce_let #> in_form) #>
   411     map (reduce_let #> in_form) #>
   465     cons (mark_builtins' ctxt term_bool_prop) #>
   412     cons (U.prop_of term_bool) #>
   466     pair (fol_rules, [term_bool])
   413     pair (fol_rules, [term_bool], builtin)
   467   end
   414   end
   468 
   415 
       
   416 end
   469 
   417 
   470 
   418 
   471 (* translation into intermediate format *)
   419 (* translation into intermediate format *)
   472 
   420 
   473 (** utility functions **)
   421 (** utility functions **)
   511   | fold_map_pat f (SNoPat ts) = fold_map f ts #>> SNoPat
   459   | fold_map_pat f (SNoPat ts) = fold_map f ts #>> SNoPat
   512 
   460 
   513 
   461 
   514 (** translation from Isabelle terms into SMT intermediate terms **)
   462 (** translation from Isabelle terms into SMT intermediate terms **)
   515 
   463 
   516 fun intermediate header dtyps ctxt ts trx =
   464 fun intermediate header dtyps builtin ctxt ts trx =
   517   let
   465   let
   518     fun transT (T as TFree _) = add_typ T true
   466     fun transT (T as TFree _) = add_typ T true
   519       | transT (T as TVar _) = (fn _ => raise TYPE ("bad SMT type", [T], []))
   467       | transT (T as TVar _) = (fn _ => raise TYPE ("bad SMT type", [T], []))
   520       | transT (T as Type _) =
   468       | transT (T as Type _) =
   521           (case B.builtin_typ ctxt T of
   469           (case B.dest_builtin_typ ctxt T of
   522             SOME n => pair n
   470             SOME n => pair n
   523           | NONE => add_typ T true)
   471           | NONE => add_typ T true)
   524 
       
   525     val unmarked_builtins = [@{const_name If}, @{const_name HOL.eq}]
       
   526 
   472 
   527     fun app n ts = SApp (n, ts)
   473     fun app n ts = SApp (n, ts)
   528 
   474 
   529     fun trans t =
   475     fun trans t =
   530       (case Term.strip_comb t of
   476       (case Term.strip_comb t of
   535               trans b #>> (fn ((Ts', ps'), b') => SQua (q, Ts', ps', w, b'))
   481               trans b #>> (fn ((Ts', ps'), b') => SQua (q, Ts', ps', w, b'))
   536           | NONE => raise TERM ("unsupported quantifier", [t]))
   482           | NONE => raise TERM ("unsupported quantifier", [t]))
   537       | (Const (@{const_name Let}, _), [t1, Abs (_, T, t2)]) =>
   483       | (Const (@{const_name Let}, _), [t1, Abs (_, T, t2)]) =>
   538           transT T ##>> trans t1 ##>> trans t2 #>>
   484           transT T ##>> trans t1 ##>> trans t2 #>>
   539           (fn ((U, u1), u2) => SLet (U, u1, u2))
   485           (fn ((U, u1), u2) => SLet (U, u1, u2))
   540       | (Var ((n, _), _), ts) => fold_map trans ts #>> app n
   486       | (u as Const (c as (_, T)), ts) =>
   541       | (u as Const (c as (n, T)), ts) =>
   487           (case builtin ctxt c ts of
   542           if member (op =) unmarked_builtins n then
   488             SOME (n, _, us, _) => fold_map trans us #>> app n
   543             (case B.builtin_fun ctxt c ts of
   489           | NONE => transs u T ts)
   544               SOME (((m, _), _), us, _) => fold_map trans us #>> app m
       
   545             | NONE => raise TERM ("not a built-in symbol", [t]))
       
   546           else transs u T ts
       
   547       | (u as Free (_, T), ts) => transs u T ts
   490       | (u as Free (_, T), ts) => transs u T ts
   548       | (Bound i, []) => pair (SVar i)
   491       | (Bound i, []) => pair (SVar i)
   549       | _ => raise TERM ("bad SMT term", [t]))
   492       | _ => raise TERM ("bad SMT term", [t]))
   550  
   493  
   551     and transs t T ts =
   494     and transs t T ts =
   588     val with_datatypes =
   531     val with_datatypes =
   589       has_datatypes andalso Config.get ctxt SMT_Config.datatypes
   532       has_datatypes andalso Config.get ctxt SMT_Config.datatypes
   590 
   533 
   591     fun no_dtyps (tr_context, ctxt) ts = (([], tr_context, ctxt), ts)
   534     fun no_dtyps (tr_context, ctxt) ts = (([], tr_context, ctxt), ts)
   592 
   535 
   593     val (builtins, ts1) =
   536     val ts1 = map (Envir.beta_eta_contract o U.prop_of o snd) ithms
   594       ithms
       
   595       |> map (Envir.beta_eta_contract o U.prop_of o snd)
       
   596       |> mark_builtins ctxt
       
   597 
   537 
   598     val ((dtyps, tr_context, ctxt1), ts2) =
   538     val ((dtyps, tr_context, ctxt1), ts2) =
   599       ((make_tr_context prefixes, ctxt), ts1)
   539       ((make_tr_context prefixes, ctxt), ts1)
   600       |-> (if with_datatypes then collect_datatypes_and_records else no_dtyps)
   540       |-> (if with_datatypes then collect_datatypes_and_records else no_dtyps)
   601 
   541 
   602     val (ctxt2, ts3) =
   542     val (ctxt2, ts3) =
   603       ts2
   543       ts2
   604       |> eta_expand
   544       |> eta_expand ctxt1
   605       |> lift_lambdas ctxt1
   545       |> lift_lambdas ctxt1
   606       ||> intro_explicit_application
   546       ||> intro_explicit_application
   607 
   547 
   608     val ((rewrite_rules, extra_thms), ts4) =
   548     val ((rewrite_rules, extra_thms, builtin), ts4) =
   609       (if is_fol then folify ctxt2 builtins else pair ([], [])) ts3
   549       (if is_fol then folify ctxt2 else pair ([], [], I)) ts3
   610 
   550 
   611     val rewrite_rules' = fun_app_eq :: rewrite_rules
   551     val rewrite_rules' = fun_app_eq :: rewrite_rules
   612   in
   552   in
   613     (ts4, tr_context)
   553     (ts4, tr_context)
   614     |-> intermediate header dtyps ctxt2
   554     |-> intermediate header dtyps (builtin B.dest_builtin) ctxt2
   615     |>> uncurry (serialize comments)
   555     |>> uncurry (serialize comments)
   616     ||> recon_of ctxt2 rewrite_rules' extra_thms ithms revert_typ revert_types
   556     ||> recon_of ctxt2 rewrite_rules' extra_thms ithms
   617   end
   557   end
   618 
   558 
   619 end
   559 end