src/Tools/subtyping.ML
author wenzelm
Mon Mar 12 11:17:59 2018 +0100 (18 months ago)
changeset 67835 c8e4ee2b5482
parent 67149 e61557884799
permissions -rw-r--r--
tuned imports;
     1 (*  Title:      Tools/subtyping.ML
     2     Author:     Dmitriy Traytel, TU Muenchen
     3 
     4 Coercive subtyping via subtype constraints.
     5 *)
     6 
     7 signature SUBTYPING =
     8 sig
     9   val coercion_enabled: bool Config.T
    10   val add_type_map: term -> Context.generic -> Context.generic
    11   val add_coercion: term -> Context.generic -> Context.generic
    12   val print_coercions: Proof.context -> unit
    13 end;
    14 
    15 structure Subtyping: SUBTYPING =
    16 struct
    17 
    18 (** coercions data **)
    19 
    20 datatype variance = COVARIANT | CONTRAVARIANT | INVARIANT | INVARIANT_TO of typ;
    21 datatype coerce_arg = PERMIT | FORBID | LEAVE
    22 
    23 datatype data = Data of
    24   {coes: (term * ((typ list * typ list) * term list)) Symreltab.table,  (*coercions table*)
    25    (*full coercions graph - only used at coercion declaration/deletion*)
    26    full_graph: int Graph.T,
    27    (*coercions graph restricted to base types - for efficiency reasons stored in the context*)
    28    coes_graph: int Graph.T,
    29    tmaps: (term * variance list) Symtab.table,  (*map functions*)
    30    coerce_args: coerce_arg list Symtab.table  (*special constants with non-coercible arguments*)};
    31 
    32 fun make_data (coes, full_graph, coes_graph, tmaps, coerce_args) =
    33   Data {coes = coes, full_graph = full_graph, coes_graph = coes_graph,
    34     tmaps = tmaps, coerce_args = coerce_args};
    35 
    36 fun merge_error_coes (a, b) =
    37   error ("Cannot merge coercion tables.\nConflicting declarations for coercions from " ^
    38     quote a ^ " to " ^ quote b ^ ".");
    39 
    40 fun merge_error_tmaps C =
    41   error ("Cannot merge coercion map tables.\nConflicting declarations for the constructor " ^
    42     quote C ^ ".");
    43 
    44 fun merge_error_coerce_args C =
    45   error ("Cannot merge tables for constants with coercion-invariant arguments.\n" ^
    46     "Conflicting declarations for the constant " ^ quote C ^ ".");
    47 
    48 structure Data = Generic_Data
    49 (
    50   type T = data;
    51   val empty = make_data (Symreltab.empty, Graph.empty, Graph.empty, Symtab.empty, Symtab.empty);
    52   val extend = I;
    53   fun merge
    54     (Data {coes = coes1, full_graph = full_graph1, coes_graph = coes_graph1,
    55       tmaps = tmaps1, coerce_args = coerce_args1},
    56       Data {coes = coes2, full_graph = full_graph2, coes_graph = coes_graph2,
    57         tmaps = tmaps2, coerce_args = coerce_args2}) =
    58     make_data (Symreltab.merge (eq_pair (op aconv)
    59         (eq_pair (eq_pair (eq_list (op =)) (eq_list (op =))) (eq_list (op aconv))))
    60         (coes1, coes2) handle Symreltab.DUP key => merge_error_coes key,
    61       Graph.merge (op =) (full_graph1, full_graph2),
    62       Graph.merge (op =) (coes_graph1, coes_graph2),
    63       Symtab.merge (eq_pair (op aconv) (op =)) (tmaps1, tmaps2)
    64         handle Symtab.DUP key => merge_error_tmaps key,
    65       Symtab.merge (eq_list (op =)) (coerce_args1, coerce_args2)
    66         handle Symtab.DUP key => merge_error_coerce_args key);
    67 );
    68 
    69 fun map_data f =
    70   Data.map (fn Data {coes, full_graph, coes_graph, tmaps, coerce_args} =>
    71     make_data (f (coes, full_graph, coes_graph, tmaps, coerce_args)));
    72 
    73 fun map_coes_and_graphs f =
    74   map_data (fn (coes, full_graph, coes_graph, tmaps, coerce_args) =>
    75     let val (coes', full_graph', coes_graph') = f (coes, full_graph, coes_graph);
    76     in (coes', full_graph', coes_graph', tmaps, coerce_args) end);
    77 
    78 fun map_tmaps f =
    79   map_data (fn (coes, full_graph, coes_graph, tmaps, coerce_args) =>
    80     (coes, full_graph, coes_graph, f tmaps, coerce_args));
    81 
    82 fun map_coerce_args f =
    83   map_data (fn (coes, full_graph, coes_graph, tmaps, coerce_args) =>
    84     (coes, full_graph, coes_graph, tmaps, f coerce_args));
    85 
    86 val rep_data = (fn Data args => args) o Data.get o Context.Proof;
    87 
    88 val coes_of = #coes o rep_data;
    89 val coes_graph_of = #coes_graph o rep_data;
    90 val tmaps_of = #tmaps o rep_data;
    91 val coerce_args_of = #coerce_args o rep_data;
    92 
    93 
    94 
    95 (** utils **)
    96 
    97 fun restrict_graph G = Graph.restrict (fn x => Graph.get_node G x = 0) G;
    98 
    99 fun nameT (Type (s, [])) = s;
   100 fun t_of s = Type (s, []);
   101 
   102 fun sort_of (TFree (_, S)) = SOME S
   103   | sort_of (TVar (_, S)) = SOME S
   104   | sort_of _ = NONE;
   105 
   106 val is_typeT = fn (Type _) => true | _ => false;
   107 val is_compT = fn (Type (_, _ :: _)) => true | _ => false;
   108 val is_freeT = fn (TFree _) => true | _ => false;
   109 val is_fixedvarT = fn (TVar (xi, _)) => not (Type_Infer.is_param xi) | _ => false;
   110 val is_funtype = fn (Type ("fun", [_, _])) => true | _ => false;
   111 
   112 fun mk_identity T = Abs (Name.uu, T, Bound 0);
   113 val is_identity = fn (Abs (_, _, Bound 0)) => true | _ => false;
   114 
   115 fun instantiate t Ts = Term.subst_TVars
   116   ((Term.add_tvar_namesT (fastype_of t) []) ~~ rev Ts) t;
   117 
   118 exception COERCION_GEN_ERROR of unit -> string * Buffer.T;
   119 
   120 infixr ++>  (*composition with deferred error message*)
   121 fun (err : unit -> string * Buffer.T) ++> s =
   122   err #> apsnd (Buffer.add s);
   123 
   124 fun eval_err err =
   125   let val (s, buf) = err ()
   126   in s ^ Markup.markup Markup.text_fold (Buffer.content buf) end;
   127 
   128 fun eval_error err = error (eval_err err);
   129 
   130 fun inst_collect tye err T U =
   131   (case (T, Type_Infer.deref tye U) of
   132     (TVar (xi, _), U) => [(xi, U)]
   133   | (Type (a, Ts), Type (b, Us)) =>
   134       if a <> b then eval_error err else inst_collects tye err Ts Us
   135   | (_, U') => if T <> U' then eval_error err else [])
   136 and inst_collects tye err Ts Us =
   137   fold2 (fn T => fn U => fn is => inst_collect tye err T U @ is) Ts Us [];
   138 
   139 
   140 (* unification *)
   141 
   142 exception NO_UNIFIER of string * typ Vartab.table;
   143 
   144 fun unify weak ctxt =
   145   let
   146     val thy = Proof_Context.theory_of ctxt;
   147     val arity_sorts = Proof_Context.arity_sorts ctxt;
   148 
   149 
   150     (* adjust sorts of parameters *)
   151 
   152     fun not_of_sort x S' S =
   153       "Variable " ^ x ^ "::" ^ Syntax.string_of_sort ctxt S' ^ " not of sort " ^
   154         Syntax.string_of_sort ctxt S;
   155 
   156     fun meet (_, []) tye_idx = tye_idx
   157       | meet (Type (a, Ts), S) (tye_idx as (tye, _)) =
   158           meets (Ts, arity_sorts a S handle ERROR msg => raise NO_UNIFIER (msg, tye)) tye_idx
   159       | meet (TFree (x, S'), S) (tye_idx as (tye, _)) =
   160           if Sign.subsort thy (S', S) then tye_idx
   161           else raise NO_UNIFIER (not_of_sort x S' S, tye)
   162       | meet (TVar (xi, S'), S) (tye_idx as (tye, idx)) =
   163           if Sign.subsort thy (S', S) then tye_idx
   164           else if Type_Infer.is_param xi then
   165             (Vartab.update_new
   166               (xi, Type_Infer.mk_param idx (Sign.inter_sort thy (S', S))) tye, idx + 1)
   167           else raise NO_UNIFIER (not_of_sort (Term.string_of_vname xi) S' S, tye)
   168     and meets (T :: Ts, S :: Ss) (tye_idx as (tye, _)) =
   169           meets (Ts, Ss) (meet (Type_Infer.deref tye T, S) tye_idx)
   170       | meets _ tye_idx = tye_idx;
   171 
   172     val weak_meet = if weak then fn _ => I else meet;
   173 
   174 
   175     (* occurs check and assignment *)
   176 
   177     fun occurs_check tye xi (TVar (xi', _)) =
   178           if xi = xi' then raise NO_UNIFIER ("Occurs check!", tye)
   179           else
   180             (case Vartab.lookup tye xi' of
   181               NONE => ()
   182             | SOME T => occurs_check tye xi T)
   183       | occurs_check tye xi (Type (_, Ts)) = List.app (occurs_check tye xi) Ts
   184       | occurs_check _ _ _ = ();
   185 
   186     fun assign xi (T as TVar (xi', _)) S env =
   187           if xi = xi' then env
   188           else env |> weak_meet (T, S) |>> Vartab.update_new (xi, T)
   189       | assign xi T S (env as (tye, _)) =
   190           (occurs_check tye xi T; env |> weak_meet (T, S) |>> Vartab.update_new (xi, T));
   191 
   192 
   193     (* unification *)
   194 
   195     fun show_tycon (a, Ts) =
   196       quote (Syntax.string_of_typ ctxt (Type (a, replicate (length Ts) dummyT)));
   197 
   198     fun unif (T1, T2) (env as (tye, _)) =
   199       (case apply2 (`Type_Infer.is_paramT o Type_Infer.deref tye) (T1, T2) of
   200         ((true, TVar (xi, S)), (_, T)) => assign xi T S env
   201       | ((_, T), (true, TVar (xi, S))) => assign xi T S env
   202       | ((_, Type (a, Ts)), (_, Type (b, Us))) =>
   203           if weak andalso null Ts andalso null Us then env
   204           else if a <> b then
   205             raise NO_UNIFIER
   206               ("Clash of types " ^ show_tycon (a, Ts) ^ " and " ^ show_tycon (b, Us), tye)
   207           else fold unif (Ts ~~ Us) env
   208       | ((_, T), (_, U)) => if T = U then env else raise NO_UNIFIER ("", tye));
   209 
   210   in unif end;
   211 
   212 val weak_unify = unify true;
   213 val strong_unify = unify false;
   214 
   215 
   216 (* Typ_Graph shortcuts *)
   217 
   218 fun get_preds G T = Typ_Graph.all_preds G [T];
   219 fun get_succs G T = Typ_Graph.all_succs G [T];
   220 fun maybe_new_typnode T G = perhaps (try (Typ_Graph.new_node (T, ()))) G;
   221 fun maybe_new_typnodes Ts G = fold maybe_new_typnode Ts G;
   222 fun new_imm_preds G Ts =  (* FIXME inefficient *)
   223   subtract (op =) Ts (distinct (op =) (maps (Typ_Graph.immediate_preds G) Ts));
   224 fun new_imm_succs G Ts =  (* FIXME inefficient *)
   225   subtract (op =) Ts (distinct (op =) (maps (Typ_Graph.immediate_succs G) Ts));
   226 
   227 
   228 (* Graph shortcuts *)
   229 
   230 fun maybe_new_node s G = perhaps (try (Graph.new_node s)) G;
   231 fun maybe_new_nodes ss G = fold maybe_new_node ss G;
   232 
   233 
   234 
   235 (** error messages **)
   236 
   237 fun gen_err err msg =
   238   err ++> ("\nNow trying to infer coercions globally.\n\nCoercion inference failed" ^
   239     (if msg = "" then "" else ":\n" ^ msg) ^ "\n");
   240 
   241 val gen_msg = eval_err oo gen_err
   242 
   243 fun prep_output ctxt tye bs ts Ts =
   244   let
   245     val (Ts_bTs', ts') = Type_Infer.finish ctxt tye (Ts @ map snd bs, ts);
   246     val (Ts', Ts'') = chop (length Ts) Ts_bTs';
   247     fun prep t =
   248       let val xs = rev (Term.variant_frees t (rev (map fst bs ~~ Ts'')))
   249       in Term.subst_bounds (map Syntax_Trans.mark_bound_abs xs, t) end;
   250   in (map prep ts', Ts') end;
   251 
   252 fun err_loose i = error ("Loose bound variable: B." ^ string_of_int i);
   253 
   254 fun unif_failed msg =
   255   "Type unification failed" ^ (if msg = "" then "" else ": " ^ msg) ^ "\n\n";
   256 
   257 fun err_appl_msg ctxt msg tye bs t T u U () =
   258   let val ([t', u'], [T', U']) = prep_output ctxt tye bs [t, u] [T, U] in
   259     (unif_failed msg ^ Type.appl_error ctxt t' T' u' U' ^ "\n\n",
   260       Buffer.empty |> Buffer.add "Coercion Inference:\n\n")
   261   end;
   262 
   263 fun err_list ctxt err tye Ts =
   264   let val (_, Ts') = prep_output ctxt tye [] [] Ts in
   265     eval_error (err ++>
   266       ("\nCannot unify a list of types that should be the same:\n" ^
   267         Pretty.string_of (Pretty.list "[" "]" (map (Syntax.pretty_typ ctxt) Ts'))))
   268   end;
   269 
   270 fun err_bound ctxt err tye packs =
   271   let
   272     val (ts, Ts) = fold
   273       (fn (bs, t $ u, U, _, U') => fn (ts, Ts) =>
   274         let val (t', T') = prep_output ctxt tye bs [t, u] [U', U]
   275         in (t' :: ts, T' :: Ts) end)
   276       packs ([], []);
   277     val msg =
   278       Pretty.string_of (Pretty.big_list "Cannot fulfil subtype constraints:"
   279         (map2 (fn [t, u] => fn [T, U] =>
   280           Pretty.block [
   281             Syntax.pretty_typ ctxt T, Pretty.brk 2, Pretty.str "<:", Pretty.brk 2,
   282             Syntax.pretty_typ ctxt U, Pretty.brk 3,
   283             Pretty.str "from function application", Pretty.brk 2,
   284             Pretty.block [Syntax.pretty_term ctxt (t $ u)]])
   285           ts Ts));
   286   in eval_error (err ++> ("\n" ^ msg)) end;
   287 
   288 
   289 
   290 (** constraint generation **)
   291 
   292 fun update_coerce_arg ctxt old t =
   293   let
   294     val mk_coerce_args = the_default [] o Symtab.lookup (coerce_args_of ctxt);
   295     fun update _ [] = old
   296       | update 0 (coerce :: _) = (case coerce of LEAVE => old | PERMIT => true | FORBID => false)
   297       | update n (_ :: cs) = update (n - 1) cs;
   298     val (f, n) = Term.strip_comb (Type.strip_constraints t) ||> length;
   299   in
   300     update n (case f of Const (name, _) => mk_coerce_args name | _ => [])
   301   end;
   302 
   303 fun generate_constraints ctxt err =
   304   let
   305     fun gen _ cs _ (Const (_, T)) tye_idx = (T, tye_idx, cs)
   306       | gen _ cs _ (Free (_, T)) tye_idx = (T, tye_idx, cs)
   307       | gen _ cs _ (Var (_, T)) tye_idx = (T, tye_idx, cs)
   308       | gen _ cs bs (Bound i) tye_idx =
   309           (snd (nth bs i handle General.Subscript => err_loose i), tye_idx, cs)
   310       | gen coerce cs bs (Abs (x, T, t)) tye_idx =
   311           let val (U, tye_idx', cs') = gen coerce cs ((x, T) :: bs) t tye_idx
   312           in (T --> U, tye_idx', cs') end
   313       | gen coerce cs bs (t $ u) tye_idx =
   314           let
   315             val (T, tye_idx', cs') = gen coerce cs bs t tye_idx;
   316             val coerce' = update_coerce_arg ctxt coerce t;
   317             val (U', (tye, idx), cs'') = gen coerce' cs' bs u tye_idx';
   318             val U = Type_Infer.mk_param idx [];
   319             val V = Type_Infer.mk_param (idx + 1) [];
   320             val tye_idx'' = strong_unify ctxt (U --> V, T) (tye, idx + 2)
   321               handle NO_UNIFIER (msg, _) => error (gen_msg err msg);
   322             val error_pack = (bs, t $ u, U, V, U');
   323           in
   324             if coerce'
   325             then (V, tye_idx'', ((U', U), error_pack) :: cs'')
   326             else (V,
   327               strong_unify ctxt (U, U') tye_idx''
   328                 handle NO_UNIFIER (msg, _) => error (gen_msg err msg),
   329               cs'')
   330           end;
   331   in
   332     gen true [] []
   333   end;
   334 
   335 
   336 
   337 (** constraint resolution **)
   338 
   339 exception BOUND_ERROR of string;
   340 
   341 fun process_constraints ctxt err cs tye_idx =
   342   let
   343     val thy = Proof_Context.theory_of ctxt;
   344 
   345     val coes_graph = coes_graph_of ctxt;
   346     val tmaps = tmaps_of ctxt;
   347     val arity_sorts = Proof_Context.arity_sorts ctxt;
   348 
   349     fun split_cs _ [] = ([], [])
   350       | split_cs f (c :: cs) =
   351           (case apply2 f (fst c) of
   352             (false, false) => apsnd (cons c) (split_cs f cs)
   353           | _ => apfst (cons c) (split_cs f cs));
   354 
   355     fun unify_list (T :: Ts) tye_idx =
   356       fold (fn U => fn tye_idx' => strong_unify ctxt (T, U) tye_idx') Ts tye_idx;
   357 
   358 
   359     (* check whether constraint simplification will terminate using weak unification *)
   360 
   361     val _ = fold (fn (TU, _) => fn tye_idx =>
   362       weak_unify ctxt TU tye_idx handle NO_UNIFIER (msg, _) =>
   363         error (gen_msg err ("weak unification of subtype constraints fails\n" ^ msg))) cs tye_idx;
   364 
   365 
   366     (* simplify constraints *)
   367 
   368     fun simplify_constraints cs tye_idx =
   369       let
   370         fun contract a Ts Us error_pack done todo tye idx =
   371           let
   372             val arg_var =
   373               (case Symtab.lookup tmaps a of
   374                 (*everything is invariant for unknown constructors*)
   375                 NONE => replicate (length Ts) INVARIANT
   376               | SOME av => snd av);
   377             fun new_constraints (variance, constraint) (cs, tye_idx) =
   378               (case variance of
   379                 COVARIANT => (constraint :: cs, tye_idx)
   380               | CONTRAVARIANT => (swap constraint :: cs, tye_idx)
   381               | INVARIANT_TO T => (cs, unify_list [T, fst constraint, snd constraint] tye_idx
   382                   handle NO_UNIFIER (msg, _) =>
   383                     err_list ctxt (gen_err err
   384                       ("failed to unify invariant arguments w.r.t. to the known map function\n" ^
   385                         msg))
   386                       (fst tye_idx) (T :: Ts))
   387               | INVARIANT => (cs, strong_unify ctxt constraint tye_idx
   388                   handle NO_UNIFIER (msg, _) =>
   389                     error (gen_msg err ("failed to unify invariant arguments\n" ^ msg))));
   390             val (new, (tye', idx')) = apfst (fn cs => (cs ~~ replicate (length cs) error_pack))
   391               (fold new_constraints (arg_var ~~ (Ts ~~ Us)) ([], (tye, idx)));
   392             val test_update = is_typeT orf is_freeT orf is_fixedvarT;
   393             val (ch, done') =
   394               done
   395               |> map (apfst (apply2 (Type_Infer.deref tye')))
   396               |> (if not (null new) then rpair []  else split_cs test_update);
   397             val todo' = ch @ todo;
   398           in
   399             simplify done' (new @ todo') (tye', idx')
   400           end
   401         (*xi is definitely a parameter*)
   402         and expand varleq xi S a Ts error_pack done todo tye idx =
   403           let
   404             val n = length Ts;
   405             val args = map2 Type_Infer.mk_param (idx upto idx + n - 1) (arity_sorts a S);
   406             val tye' = Vartab.update_new (xi, Type(a, args)) tye;
   407             val (ch, done') = split_cs (is_compT o Type_Infer.deref tye') done;
   408             val todo' = ch @ todo;
   409             val new =
   410               if varleq then (Type(a, args), Type (a, Ts))
   411               else (Type (a, Ts), Type (a, args));
   412           in
   413             simplify done' ((new, error_pack) :: todo') (tye', idx + n)
   414           end
   415         (*TU is a pair of a parameter and a free/fixed variable*)
   416         and eliminate TU done todo tye idx =
   417           let
   418             val [TVar (xi, S)] = filter Type_Infer.is_paramT TU;
   419             val [T] = filter_out Type_Infer.is_paramT TU;
   420             val SOME S' = sort_of T;
   421             val test_update = if is_freeT T then is_freeT else is_fixedvarT;
   422             val tye' = Vartab.update_new (xi, T) tye;
   423             val (ch, done') = split_cs (test_update o Type_Infer.deref tye') done;
   424             val todo' = ch @ todo;
   425           in
   426             if Sign.subsort thy (S', S) (*TODO check this*)
   427             then simplify done' todo' (tye', idx)
   428             else error (gen_msg err "sort mismatch")
   429           end
   430         and simplify done [] tye_idx = (done, tye_idx)
   431           | simplify done (((T, U), error_pack) :: todo) (tye_idx as (tye, idx)) =
   432               (case (Type_Infer.deref tye T, Type_Infer.deref tye U) of
   433                 (T1 as Type (a, []), T2 as Type (b, [])) =>
   434                   if a = b then simplify done todo tye_idx
   435                   else if Graph.is_edge coes_graph (a, b) then simplify done todo tye_idx
   436                   else
   437                     error (gen_msg err (quote (Syntax.string_of_typ ctxt T1) ^
   438                       " is not a subtype of " ^ quote (Syntax.string_of_typ ctxt T2)))
   439               | (Type (a, Ts), Type (b, Us)) =>
   440                   if a <> b then
   441                     error (gen_msg err "different constructors") (fst tye_idx) error_pack
   442                   else contract a Ts Us error_pack done todo tye idx
   443               | (TVar (xi, S), Type (a, Ts as (_ :: _))) =>
   444                   expand true xi S a Ts error_pack done todo tye idx
   445               | (Type (a, Ts as (_ :: _)), TVar (xi, S)) =>
   446                   expand false xi S a Ts error_pack done todo tye idx
   447               | (T, U) =>
   448                   if T = U then simplify done todo tye_idx
   449                   else if exists (is_freeT orf is_fixedvarT) [T, U] andalso
   450                     exists Type_Infer.is_paramT [T, U]
   451                   then eliminate [T, U] done todo tye idx
   452                   else if exists (is_freeT orf is_fixedvarT) [T, U]
   453                   then error (gen_msg err "not eliminated free/fixed variables")
   454                   else simplify (((T, U), error_pack) :: done) todo tye_idx);
   455       in
   456         simplify [] cs tye_idx
   457       end;
   458 
   459 
   460     (* do simplification *)
   461 
   462     val (cs', tye_idx') = simplify_constraints cs tye_idx;
   463 
   464     fun find_error_pack lower T' = map_filter
   465       (fn ((T, U), pack) => if if lower then T' = U else T' = T then SOME pack else NONE) cs';
   466 
   467     fun find_cycle_packs nodes =
   468       let
   469         val (but_last, last) = split_last nodes
   470         val pairs = (last, hd nodes) :: (but_last ~~ tl nodes);
   471       in
   472         map_filter
   473           (fn (TU, pack) => if member (op =) pairs TU then SOME pack else NONE)
   474           cs'
   475       end;
   476 
   477     (*styps stands either for supertypes or for subtypes of a type T
   478       in terms of the subtype-relation (excluding T itself)*)
   479     fun styps super T =
   480       (if super then Graph.immediate_succs else Graph.immediate_preds) coes_graph T
   481         handle Graph.UNDEF _ => [];
   482 
   483     fun minmax sup (T :: Ts) =
   484       let
   485         fun adjust T U = if sup then (T, U) else (U, T);
   486         fun extract T [] = T
   487           | extract T (U :: Us) =
   488               if Graph.is_edge coes_graph (adjust T U) then extract T Us
   489               else if Graph.is_edge coes_graph (adjust U T) then extract U Us
   490               else raise BOUND_ERROR "uncomparable types in type list";
   491       in
   492         t_of (extract T Ts)
   493       end;
   494 
   495     fun ex_styp_of_sort super T styps_and_sorts =
   496       let
   497         fun adjust T U = if super then (T, U) else (U, T);
   498         fun styp_test U Ts = forall
   499           (fn T => T = U orelse Graph.is_edge coes_graph (adjust U T)) Ts;
   500         fun fitting Ts S U = Sign.of_sort thy (t_of U, S) andalso styp_test U Ts;
   501       in
   502         forall (fn (Ts, S) => exists (fitting Ts S) (T :: styps super T)) styps_and_sorts
   503       end;
   504 
   505     (* computes the tightest possible, correct assignment for 'a::S
   506        e.g. in the supremum case (sup = true):
   507                ------- 'a::S---
   508               /        /    \  \
   509              /        /      \  \
   510         'b::C1   'c::C2 ...  T1 T2 ...
   511 
   512        sorts - list of sorts [C1, C2, ...]
   513        T::Ts - non-empty list of base types [T1, T2, ...]
   514     *)
   515     fun tightest sup S styps_and_sorts (T :: Ts) =
   516       let
   517         fun restriction T = Sign.of_sort thy (t_of T, S)
   518           andalso ex_styp_of_sort (not sup) T styps_and_sorts;
   519         fun candidates T = inter (op =) (filter restriction (T :: styps sup T));
   520       in
   521         (case fold candidates Ts (filter restriction (T :: styps sup T)) of
   522           [] => raise BOUND_ERROR ("no " ^ (if sup then "supremum" else "infimum"))
   523         | [T] => t_of T
   524         | Ts => minmax sup Ts)
   525       end;
   526 
   527     fun build_graph G [] tye_idx = (G, tye_idx)
   528       | build_graph G ((T, U) :: cs) tye_idx =
   529         if T = U then build_graph G cs tye_idx
   530         else
   531           let
   532             val G' = maybe_new_typnodes [T, U] G;
   533             val (G'', tye_idx') = (Typ_Graph.add_edge_acyclic (T, U) G', tye_idx)
   534               handle Typ_Graph.CYCLES cycles =>
   535                 let
   536                   val (tye, idx) =
   537                     fold
   538                       (fn cycle => fn tye_idx' => (unify_list cycle tye_idx'
   539                         handle NO_UNIFIER (msg, _) =>
   540                           err_bound ctxt
   541                             (gen_err err ("constraint cycle not unifiable\n" ^ msg)) (fst tye_idx)
   542                             (find_cycle_packs cycle)))
   543                       cycles tye_idx
   544                 in
   545                   collapse (tye, idx) cycles G
   546                 end
   547           in
   548             build_graph G'' cs tye_idx'
   549           end
   550     and collapse (tye, idx) cycles G = (*nodes non-empty list*)
   551       let
   552         (*all cycles collapse to one node,
   553           because all of them share at least the nodes x and y*)
   554         val nodes = (distinct (op =) (flat cycles));
   555         val T = Type_Infer.deref tye (hd nodes);
   556         val P = new_imm_preds G nodes;
   557         val S = new_imm_succs G nodes;
   558         val G' = fold Typ_Graph.del_node (tl nodes) G;
   559         fun check_and_gen super T' =
   560           let val U = Type_Infer.deref tye T';
   561           in
   562             if not (is_typeT T) orelse not (is_typeT U) orelse T = U
   563             then if super then (hd nodes, T') else (T', hd nodes)
   564             else
   565               if super andalso
   566                 Graph.is_edge coes_graph (nameT T, nameT U) then (hd nodes, T')
   567               else if not super andalso
   568                 Graph.is_edge coes_graph (nameT U, nameT T) then (T', hd nodes)
   569               else
   570                 err_bound ctxt (gen_err err "cycle elimination produces inconsistent graph")
   571                   (fst tye_idx)
   572                   (maps find_cycle_packs cycles @ find_error_pack super T')
   573           end;
   574       in
   575         build_graph G' (map (check_and_gen false) P @ map (check_and_gen true) S) (tye, idx)
   576       end;
   577 
   578     fun assign_bound lower G key (tye_idx as (tye, _)) =
   579       if Type_Infer.is_paramT (Type_Infer.deref tye key) then
   580         let
   581           val TVar (xi, S) = Type_Infer.deref tye key;
   582           val get_bound = if lower then get_preds else get_succs;
   583           val raw_bound = get_bound G key;
   584           val bound = map (Type_Infer.deref tye) raw_bound;
   585           val not_params = filter_out Type_Infer.is_paramT bound;
   586           fun to_fulfil T =
   587             (case sort_of T of
   588               NONE => NONE
   589             | SOME S =>
   590                 SOME
   591                   (map nameT
   592                     (filter_out Type_Infer.is_paramT
   593                       (map (Type_Infer.deref tye) (get_bound G T))), S));
   594           val styps_and_sorts = distinct (op =) (map_filter to_fulfil raw_bound);
   595           val assignment =
   596             if null bound orelse null not_params then NONE
   597             else SOME (tightest lower S styps_and_sorts (map nameT not_params)
   598                 handle BOUND_ERROR msg => err_bound ctxt (gen_err err msg) tye
   599                   (maps (find_error_pack (not lower)) raw_bound));
   600         in
   601           (case assignment of
   602             NONE => tye_idx
   603           | SOME T =>
   604               if Type_Infer.is_paramT T then tye_idx
   605               else if lower then (*upper bound check*)
   606                 let
   607                   val other_bound = map (Type_Infer.deref tye) (get_succs G key);
   608                   val s = nameT T;
   609                 in
   610                   if subset (op = o apfst nameT) (filter is_typeT other_bound, s :: styps true s)
   611                   then apfst (Vartab.update (xi, T)) tye_idx
   612                   else
   613                     err_bound ctxt
   614                       (gen_err err
   615                         (Pretty.string_of (Pretty.block
   616                           [Pretty.str "assigned base type", Pretty.brk 1,
   617                             Pretty.quote (Syntax.pretty_typ ctxt T), Pretty.brk 1,
   618                             Pretty.str "clashes with the upper bound of variable", Pretty.brk 1,
   619                             Syntax.pretty_typ ctxt (TVar (xi, S))])))
   620                       tye
   621                       (maps (find_error_pack lower) other_bound)
   622                 end
   623               else apfst (Vartab.update (xi, T)) tye_idx)
   624         end
   625       else tye_idx;
   626 
   627     val assign_lb = assign_bound true;
   628     val assign_ub = assign_bound false;
   629 
   630     fun assign_alternating ts' ts G tye_idx =
   631       if ts' = ts then tye_idx
   632       else
   633         let
   634           val (tye_idx' as (tye, _)) = fold (assign_lb G) ts tye_idx
   635             |> fold (assign_ub G) ts;
   636         in
   637           assign_alternating ts
   638             (filter (Type_Infer.is_paramT o Type_Infer.deref tye) ts) G tye_idx'
   639         end;
   640 
   641     (*Unify all weakly connected components of the constraint forest,
   642       that contain only params. These are the only WCCs that contain
   643       params anyway.*)
   644     fun unify_params G (tye_idx as (tye, _)) =
   645       let
   646         val max_params =
   647           filter (Type_Infer.is_paramT o Type_Infer.deref tye) (Typ_Graph.maximals G);
   648         val to_unify = map (fn T => T :: get_preds G T) max_params;
   649       in
   650         fold
   651           (fn Ts => fn tye_idx' => unify_list Ts tye_idx'
   652             handle NO_UNIFIER (msg, _) => err_list ctxt (gen_err err msg) (fst tye_idx) Ts)
   653           to_unify tye_idx
   654       end;
   655 
   656     fun solve_constraints G tye_idx = tye_idx
   657       |> assign_alternating [] (Typ_Graph.keys G) G
   658       |> unify_params G;
   659   in
   660     build_graph Typ_Graph.empty (map fst cs') tye_idx'
   661       |-> solve_constraints
   662   end;
   663 
   664 
   665 
   666 (** coercion insertion **)
   667 
   668 fun gen_coercion ctxt err tye TU =
   669   let
   670     fun gen (T1, T2) =
   671       (case apply2 (Type_Infer.deref tye) (T1, T2) of
   672         (T1 as (Type (a, [])), T2 as (Type (b, []))) =>
   673             if a = b
   674             then mk_identity T1
   675             else
   676               (case Symreltab.lookup (coes_of ctxt) (a, b) of
   677                 NONE =>
   678                   raise COERCION_GEN_ERROR (err ++>
   679                     (Pretty.string_of o Pretty.block)
   680                       [Pretty.quote (Syntax.pretty_typ ctxt T1), Pretty.brk 1,
   681                         Pretty.str "is not a subtype of", Pretty.brk 1,
   682                         Pretty.quote (Syntax.pretty_typ ctxt T2)])
   683               | SOME (co, _) => co)
   684       | (T1 as Type (a, Ts), T2 as Type (b, Us)) =>
   685             if a <> b
   686             then
   687               (case Symreltab.lookup (coes_of ctxt) (a, b) of
   688                 (*immediate error - cannot fix complex coercion with the global algorithm*)
   689                 NONE =>
   690                   eval_error (err ++>
   691                     ("No coercion known for type constructors: " ^
   692                       quote (Proof_Context.markup_type ctxt a) ^ " and " ^
   693                       quote (Proof_Context.markup_type ctxt b)))
   694               | SOME (co, ((Ts', Us'), _)) =>
   695                   let
   696                     val co_before = gen (T1, Type (a, Ts'));
   697                     val coT = range_type (fastype_of co_before);
   698                     val insts =
   699                       inst_collect tye (err ++> "Could not insert complex coercion")
   700                         (domain_type (fastype_of co)) coT;
   701                     val co' = Term.subst_TVars insts co;
   702                     val co_after = gen (Type (b, (map (typ_subst_TVars insts) Us')), T2);
   703                   in
   704                     Abs (Name.uu, T1, Library.foldr (op $)
   705                       (filter (not o is_identity) [co_after, co', co_before], Bound 0))
   706                   end)
   707             else
   708               let
   709                 fun sub_co (COVARIANT, TU) = (SOME (gen TU), NONE)
   710                   | sub_co (CONTRAVARIANT, TU) = (SOME (gen (swap TU)), NONE)
   711                   | sub_co (INVARIANT, (T, _)) = (NONE, SOME T)
   712                   | sub_co (INVARIANT_TO T, _) = (NONE, NONE);
   713                 fun ts_of [] = []
   714                   | ts_of (Type ("fun", [x1, x2]) :: xs) = x1 :: x2 :: (ts_of xs);
   715               in
   716                 (case Symtab.lookup (tmaps_of ctxt) a of
   717                   NONE =>
   718                     if Type.could_unify (T1, T2)
   719                     then mk_identity T1
   720                     else
   721                       raise COERCION_GEN_ERROR
   722                         (err ++>
   723                           ("No map function for " ^ quote (Proof_Context.markup_type ctxt a)
   724                             ^ " known"))
   725                 | SOME (tmap, variances) =>
   726                     let
   727                       val (used_coes, invarTs) =
   728                         map_split sub_co (variances ~~ (Ts ~~ Us))
   729                         |>> map_filter I
   730                         ||> map_filter I;
   731                       val Tinsts = ts_of (map fastype_of used_coes) @ invarTs;
   732                     in
   733                       if null (filter (not o is_identity) used_coes)
   734                       then mk_identity (Type (a, Ts))
   735                       else Term.list_comb (instantiate tmap Tinsts, used_coes)
   736                     end)
   737               end
   738       | (T, U) =>
   739             if Type.could_unify (T, U)
   740             then mk_identity T
   741             else raise COERCION_GEN_ERROR (err ++>
   742               (Pretty.string_of o Pretty.block)
   743                [Pretty.str "Cannot generate coercion from", Pretty.brk 1,
   744                 Pretty.quote (Syntax.pretty_typ ctxt T), Pretty.brk 1,
   745                 Pretty.str "to", Pretty.brk 1,
   746                 Pretty.quote (Syntax.pretty_typ ctxt U)]));
   747   in
   748     gen TU
   749   end;
   750 
   751 fun function_of ctxt err tye T =
   752   (case Type_Infer.deref tye T of
   753     Type (C, Ts) =>
   754       (case Symreltab.lookup (coes_of ctxt) (C, "fun") of
   755         NONE =>
   756           eval_error (err ++> ("No complex coercion from " ^
   757             quote (Proof_Context.markup_type ctxt C) ^ " to " ^
   758             quote (Proof_Context.markup_type ctxt "fun")))
   759       | SOME (co, ((Ts', _), _)) =>
   760         let
   761           val co_before = gen_coercion ctxt err tye (Type (C, Ts), Type (C, Ts'));
   762           val coT = range_type (fastype_of co_before);
   763           val insts =
   764             inst_collect tye (err ++> "Could not insert complex coercion")
   765               (domain_type (fastype_of co)) coT;
   766           val co' = Term.subst_TVars insts co;
   767         in
   768           Abs (Name.uu, Type (C, Ts), Library.foldr (op $)
   769             (filter (not o is_identity) [co', co_before], Bound 0))
   770         end)
   771   | T' =>
   772       eval_error (err ++>
   773         (Pretty.string_of o Pretty.block)
   774          [Pretty.str "No complex coercion from", Pretty.brk 1,
   775           Pretty.quote (Syntax.pretty_typ ctxt T'), Pretty.brk 1,
   776           Pretty.str "to", Pretty.brk 1, Proof_Context.pretty_type ctxt "fun"]));
   777 
   778 fun insert_coercions ctxt (tye, idx) ts =
   779   let
   780     fun insert _ (Const (c, T)) = (Const (c, T), T)
   781       | insert _ (Free (x, T)) = (Free (x, T), T)
   782       | insert _ (Var (xi, T)) = (Var (xi, T), T)
   783       | insert bs (Bound i) =
   784           let val T = nth bs i handle General.Subscript => err_loose i;
   785           in (Bound i, T) end
   786       | insert bs (Abs (x, T, t)) =
   787           let val (t', T') = insert (T :: bs) t;
   788           in (Abs (x, T, t'), T --> T') end
   789       | insert bs (t $ u) =
   790           let
   791             val (t', Type ("fun", [U, T])) = apsnd (Type_Infer.deref tye) (insert bs t);
   792             val (u', U') = insert bs u;
   793           in
   794             if can (fn TU => strong_unify ctxt TU (tye, 0)) (U, U')
   795             then (t' $ u', T)
   796             else (t' $ (gen_coercion ctxt (K ("", Buffer.empty)) tye (U', U) $ u'), T)
   797           end
   798   in
   799     map (fst o insert []) ts
   800   end;
   801 
   802 
   803 
   804 (** assembling the pipeline **)
   805 
   806 fun coercion_infer_types ctxt raw_ts =
   807   let
   808     val (idx, ts) = Type_Infer_Context.prepare ctxt raw_ts;
   809 
   810     fun inf _ _ (t as (Const (_, T))) tye_idx = (t, T, tye_idx)
   811       | inf _ _ (t as (Free (_, T))) tye_idx = (t, T, tye_idx)
   812       | inf _ _ (t as (Var (_, T))) tye_idx = (t, T, tye_idx)
   813       | inf _ bs (t as (Bound i)) tye_idx =
   814           (t, snd (nth bs i handle General.Subscript => err_loose i), tye_idx)
   815       | inf coerce bs (Abs (x, T, t)) tye_idx =
   816           let val (t', U, tye_idx') = inf coerce ((x, T) :: bs) t tye_idx
   817           in (Abs (x, T, t'), T --> U, tye_idx') end
   818       | inf coerce bs (t $ u) tye_idx =
   819           let
   820             val (t', T, tye_idx') = inf coerce bs t tye_idx;
   821             val coerce' = update_coerce_arg ctxt coerce t;
   822             val (u', U, (tye, idx)) = inf coerce' bs u tye_idx';
   823             val V = Type_Infer.mk_param idx [];
   824             val (tu, tye_idx'') = (t' $ u', strong_unify ctxt (U --> V, T) (tye, idx + 1))
   825               handle NO_UNIFIER (msg, tye') =>
   826                 let
   827                   val err = err_appl_msg ctxt msg tye' bs t T u U;
   828                   val W = Type_Infer.mk_param (idx + 1) [];
   829                   val (t'', (tye', idx')) =
   830                     (t', strong_unify ctxt (W --> V, T) (tye, idx + 2))
   831                       handle NO_UNIFIER _ =>
   832                         let
   833                           val err' = err ++> "Local coercion insertion on the operator failed:\n";
   834                           val co = function_of ctxt err' tye T;
   835                           val (t'', T'', tye_idx'') = inf coerce bs (co $ t') (tye, idx + 2);
   836                         in
   837                           (t'', strong_unify ctxt (W --> V, T'') tye_idx''
   838                             handle NO_UNIFIER (msg, _) => eval_error (err' ++> msg))
   839                         end;
   840                   val err' = err ++>
   841                     ((if t' aconv t'' then ""
   842                       else "Successfully coerced the operator to a function of type:\n" ^
   843                         Syntax.string_of_typ ctxt
   844                           (the_single (snd (prep_output ctxt tye' bs [] [W --> V]))) ^ "\n") ^
   845                      (if coerce' then "Local coercion insertion on the operand failed:\n"
   846                       else "Local coercion insertion on the operand disallowed:\n"));
   847                   val (u'', U', tye_idx') =
   848                     if coerce' then
   849                       let val co = gen_coercion ctxt err' tye' (U, W);
   850                       in inf coerce' bs (if is_identity co then u else co $ u) (tye', idx') end
   851                     else (u, U, (tye', idx'));
   852                 in
   853                   (t'' $ u'', strong_unify ctxt (U', W) tye_idx'
   854                     handle NO_UNIFIER (msg, _) => raise COERCION_GEN_ERROR (err' ++> msg))
   855                 end;
   856           in (tu, V, tye_idx'') end;
   857 
   858     fun infer_single t tye_idx =
   859       let val (t, _, tye_idx') = inf true [] t tye_idx
   860       in (t, tye_idx') end;
   861 
   862     val (ts', (tye, _)) = (fold_map infer_single ts (Vartab.empty, idx)
   863       handle COERCION_GEN_ERROR err =>
   864         let
   865           fun gen_single t (tye_idx, constraints) =
   866             let val (_, tye_idx', constraints') =
   867               generate_constraints ctxt (err ++> "\n") t tye_idx
   868             in (tye_idx', constraints' @ constraints) end;
   869 
   870           val (tye_idx, constraints) = fold gen_single ts ((Vartab.empty, idx), []);
   871           val (tye, idx) = process_constraints ctxt (err ++> "\n") constraints tye_idx;
   872         in
   873           (insert_coercions ctxt (tye, idx) ts, (tye, idx))
   874         end);
   875 
   876     val (_, ts'') = Type_Infer.finish ctxt tye ([], ts');
   877   in ts'' end;
   878 
   879 
   880 
   881 (** installation **)
   882 
   883 (* term check *)
   884 
   885 val coercion_enabled = Attrib.setup_config_bool \<^binding>\<open>coercion_enabled\<close> (K false);
   886 
   887 val _ =
   888   Theory.setup
   889     (Context.theory_map
   890       (Syntax_Phases.term_check ~100 "coercions"
   891         (fn ctxt => Config.get ctxt coercion_enabled ? coercion_infer_types ctxt)));
   892 
   893 
   894 (* declarations *)
   895 
   896 fun add_type_map raw_t context =
   897   let
   898     val ctxt = Context.proof_of context;
   899     val t = singleton (Variable.polymorphic ctxt) raw_t;
   900 
   901     fun err_str t = "\n\nThe provided function has the type:\n" ^
   902       Syntax.string_of_typ ctxt (fastype_of t) ^
   903       "\n\nThe general type signature of a map function is:" ^
   904       "\nf1 => f2 => ... => fn => C [x1, ..., xn] => C [y1, ..., yn]" ^
   905       "\nwhere C is a constructor and fi is of type (xi => yi) or (yi => xi).";
   906 
   907     val ((fis, T1), T2) = apfst split_last (strip_type (fastype_of t))
   908       handle List.Empty => error ("Not a proper map function:" ^ err_str t);
   909 
   910     fun gen_arg_var ([], []) = []
   911       | gen_arg_var (Ts, (U, U') :: Us) =
   912           if U = U' then
   913             if null (Term.add_tvarsT U []) then INVARIANT_TO U :: gen_arg_var (Ts, Us)
   914             else if Term.is_TVar U then INVARIANT :: gen_arg_var (Ts, Us)
   915             else error ("Invariant xi and yi should be variables or variable-free:" ^ err_str t)
   916           else
   917             (case Ts of
   918               [] => error ("Different numbers of functions and variant arguments\n" ^ err_str t)
   919             | (T, T') :: Ts =>
   920               if T = U andalso T' = U' then COVARIANT :: gen_arg_var (Ts, Us)
   921               else if T = U' andalso T' = U then CONTRAVARIANT :: gen_arg_var (Ts, Us)
   922               else error ("Functions do not apply to arguments correctly:" ^ err_str t));
   923 
   924     (*retry flag needed to adjust the type lists, when given a map over type constructor fun*)
   925     fun check_map_fun fis (Type (C1, Ts)) (Type (C2, Us)) _ =
   926           if C1 = C2 andalso not (null fis) andalso forall is_funtype fis
   927           then ((map dest_funT fis, Ts ~~ Us), C1)
   928           else error ("Not a proper map function:" ^ err_str t)
   929       | check_map_fun fis T1 T2 true =
   930           let val (fis', T') = split_last fis
   931           in check_map_fun fis' T' (T1 --> T2) false end
   932       | check_map_fun _ _ _ _ = error ("Not a proper map function:" ^ err_str t);
   933 
   934     val res = check_map_fun fis T1 T2 true;
   935     val res_av = gen_arg_var (fst res);
   936   in
   937     map_tmaps (Symtab.update (snd res, (t, res_av))) context
   938   end;
   939 
   940 fun transitive_coercion ctxt tab G (a, b) =
   941   let
   942     fun safe_app t (Abs (x, T', u)) =
   943       let
   944         val t' = map_types Type_Infer.paramify_vars t;
   945       in
   946         singleton (coercion_infer_types ctxt) (Abs(x, T', (t' $ u)))
   947       end;
   948     val path = hd (Graph.irreducible_paths G (a, b));
   949     val path' = fst (split_last path) ~~ tl path;
   950     val coercions = map (fst o the o Symreltab.lookup tab) path';
   951     val trans_co = singleton (Variable.polymorphic ctxt)
   952       (fold safe_app coercions (mk_identity dummyT));
   953     val (Ts, Us) = apply2 (snd o Term.dest_Type) (Term.dest_funT (type_of trans_co));
   954   in
   955     (trans_co, ((Ts, Us), coercions))
   956   end;
   957 
   958 fun add_coercion raw_t context =
   959   let
   960     val ctxt = Context.proof_of context;
   961     val t = singleton (Variable.polymorphic ctxt) raw_t;
   962 
   963     fun err_coercion () =
   964       error ("Bad type for a coercion:\n" ^
   965         Syntax.string_of_term ctxt t ^ " :: " ^
   966         Syntax.string_of_typ ctxt (fastype_of t));
   967 
   968     val (T1, T2) = Term.dest_funT (fastype_of t)
   969       handle TYPE _ => err_coercion ();
   970 
   971     val (a, Ts) = Term.dest_Type T1
   972       handle TYPE _ => err_coercion ();
   973 
   974     val (b, Us) = Term.dest_Type T2
   975       handle TYPE _ => err_coercion ();
   976 
   977     fun coercion_data_update (tab, G, _) =
   978       let
   979         val G' = maybe_new_nodes [(a, length Ts), (b, length Us)] G
   980         val G'' = Graph.add_edge_trans_acyclic (a, b) G'
   981           handle Graph.CYCLES _ => error (
   982             Syntax.string_of_typ ctxt T2 ^ " is already a subtype of " ^
   983             Syntax.string_of_typ ctxt T1 ^ "!\n\nCannot add coercion of type: " ^
   984             Syntax.string_of_typ ctxt (T1 --> T2));
   985         val new_edges =
   986           flat (Graph.dest G'' |> map (fn ((x, _), ys) => ys |> map_filter (fn y =>
   987             if Graph.is_edge G' (x, y) then NONE else SOME (x, y))));
   988         val G_and_new = Graph.add_edge (a, b) G';
   989 
   990         val tab' = fold
   991           (fn pair => fn tab =>
   992             Symreltab.update (pair, transitive_coercion ctxt tab G_and_new pair) tab)
   993           (filter (fn pair => pair <> (a, b)) new_edges)
   994           (Symreltab.update ((a, b), (t, ((Ts, Us), []))) tab);
   995       in
   996         (tab', G'', restrict_graph G'')
   997       end;
   998   in
   999     map_coes_and_graphs coercion_data_update context
  1000   end;
  1001 
  1002 fun delete_coercion raw_t context =
  1003   let
  1004     val ctxt = Context.proof_of context;
  1005     val t = singleton (Variable.polymorphic ctxt) raw_t;
  1006 
  1007     fun err_coercion the =
  1008       error ("Not" ^
  1009         (if the then " the defined " else  " a ") ^ "coercion:\n" ^
  1010         Syntax.string_of_term ctxt t ^ " :: " ^
  1011         Syntax.string_of_typ ctxt (fastype_of t));
  1012 
  1013     val (T1, T2) = Term.dest_funT (fastype_of t)
  1014       handle TYPE _ => err_coercion false;
  1015 
  1016     val (a, _) = dest_Type T1
  1017       handle TYPE _ => err_coercion false;
  1018 
  1019     val (b, _) = dest_Type T2
  1020       handle TYPE _ => err_coercion false;
  1021 
  1022     fun delete_and_insert tab G =
  1023       let
  1024         val pairs =
  1025           Symreltab.fold (fn ((a, b), (_, (_, ts))) => fn pairs =>
  1026             if member (op aconv) ts t then (a, b) :: pairs else pairs) tab [(a, b)];
  1027         fun delete pair (G, tab) = (Graph.del_edge pair G, Symreltab.delete_safe pair tab);
  1028         val (G', tab') = fold delete pairs (G, tab);
  1029         fun reinsert pair (G, xs) =
  1030           (case Graph.irreducible_paths G pair of
  1031             [] => (G, xs)
  1032           | _ => (Graph.add_edge pair G, (pair, transitive_coercion ctxt tab' G' pair) :: xs));
  1033         val (G'', ins) = fold reinsert pairs (G', []);
  1034       in
  1035         (fold Symreltab.update ins tab', G'', restrict_graph G'')
  1036       end
  1037 
  1038     fun show_term t =
  1039       Pretty.block [Syntax.pretty_term ctxt t,
  1040         Pretty.str " :: ", Syntax.pretty_typ ctxt (fastype_of t)];
  1041 
  1042     fun coercion_data_update (tab, G, _) =
  1043       (case Symreltab.lookup tab (a, b) of
  1044         NONE => err_coercion false
  1045       | SOME (t', (_, [])) =>
  1046           if t aconv t'
  1047           then delete_and_insert tab G
  1048           else err_coercion true
  1049       | SOME (t', (_, ts)) =>
  1050           if t aconv t' then
  1051             error ("Cannot delete the automatically derived coercion:\n" ^
  1052               Syntax.string_of_term ctxt t ^ " :: " ^
  1053               Syntax.string_of_typ ctxt (fastype_of t) ^ "\n\n" ^
  1054               Pretty.string_of
  1055                 (Pretty.big_list "Deleting one of the coercions:" (map show_term ts)) ^
  1056               "\nwill also remove the transitive coercion.")
  1057           else err_coercion true);
  1058   in
  1059     map_coes_and_graphs coercion_data_update context
  1060   end;
  1061 
  1062 fun print_coercions ctxt =
  1063   let
  1064     fun separate _ [] = ([], [])
  1065       | separate P (x :: xs) = (if P x then apfst else apsnd) (cons x) (separate P xs);
  1066     val (simple, complex) =
  1067       separate (fn (_, (_, ((Ts, Us), _))) => null Ts andalso null Us)
  1068         (Symreltab.dest (coes_of ctxt));
  1069     fun show_coercion ((a, b), (t, ((Ts, Us), _))) =
  1070       Pretty.item [Pretty.block
  1071        [Syntax.pretty_typ ctxt (Type (a, Ts)), Pretty.brk 1,
  1072         Pretty.str "<:", Pretty.brk 1,
  1073         Syntax.pretty_typ ctxt (Type (b, Us)), Pretty.brk 3,
  1074         Pretty.block
  1075          [Pretty.keyword2 "using", Pretty.brk 1,
  1076           Pretty.quote (Syntax.pretty_term ctxt t)]]];
  1077 
  1078     val type_space = Proof_Context.type_space ctxt;
  1079     val tmaps =
  1080       sort (Name_Space.extern_ord ctxt type_space o apply2 #1)
  1081         (Symtab.dest (tmaps_of ctxt));
  1082     fun show_map (c, (t, _)) =
  1083       Pretty.block
  1084        [Name_Space.pretty ctxt type_space c, Pretty.str ":",
  1085         Pretty.brk 1, Pretty.quote (Syntax.pretty_term ctxt t)];
  1086   in
  1087    [Pretty.big_list "coercions between base types:" (map show_coercion simple),
  1088     Pretty.big_list "other coercions:" (map show_coercion complex),
  1089     Pretty.big_list "coercion maps:" (map show_map tmaps)]
  1090   end |> Pretty.writeln_chunks;
  1091 
  1092 
  1093 (* attribute setup *)
  1094 
  1095 val parse_coerce_args =
  1096   Args.$$$ "+" >> K PERMIT || Args.$$$ "-" >> K FORBID || Args.$$$ "0" >> K LEAVE
  1097 
  1098 val _ =
  1099   Theory.setup
  1100    (Attrib.setup \<^binding>\<open>coercion\<close>
  1101       (Args.term >> (fn t => Thm.declaration_attribute (K (add_coercion t))))
  1102       "declaration of new coercions" #>
  1103     Attrib.setup \<^binding>\<open>coercion_delete\<close>
  1104       (Args.term >> (fn t => Thm.declaration_attribute (K (delete_coercion t))))
  1105       "deletion of coercions" #>
  1106     Attrib.setup \<^binding>\<open>coercion_map\<close>
  1107       (Args.term >> (fn t => Thm.declaration_attribute (K (add_type_map t))))
  1108       "declaration of new map functions" #>
  1109     Attrib.setup \<^binding>\<open>coercion_args\<close>
  1110       (Args.const {proper = false, strict = false} -- Scan.lift (Scan.repeat1 parse_coerce_args) >>
  1111         (fn spec => Thm.declaration_attribute (K (map_coerce_args (Symtab.update spec)))))
  1112       "declaration of new constants with coercion-invariant arguments");
  1113 
  1114 
  1115 (* outer syntax commands *)
  1116 
  1117 val _ =
  1118   Outer_Syntax.command \<^command_keyword>\<open>print_coercions\<close>
  1119     "print information about coercions"
  1120     (Scan.succeed (Toplevel.keep (print_coercions o Toplevel.context_of)));
  1121 
  1122 end;