merged
authorwenzelm
Wed, 01 Dec 2010 15:38:05 +0100
changeset 40847 df8c7dc30214
parent 40846 5a2ae8cc9d0e (current diff)
parent 40845 15b97bd4b5c0 (diff)
child 40848 8662b9b1f123
child 40854 f2c9ebbe04aa
child 41160 be34449f6cba
merged
--- a/src/CCL/CCL.thy	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/CCL/CCL.thy	Wed Dec 01 15:38:05 2010 +0100
@@ -233,7 +233,7 @@
          | arg_str 1 a s = "(" ^ a ^ "a" ^ s ^ ")"
          | arg_str n a s = arg_str (n-1) a ("," ^ a ^ (chr((ord "a")+n-1)) ^ s)
            val T = Sign.the_const_type thy (Sign.intern_const thy sy);
-           val arity = length (fst (strip_type T))
+           val arity = length (binder_types T)
        in sy ^ (arg_str arity name "") end
 
   fun mk_thm_str thy a b = "~ " ^ (saturate thy a "a") ^ " = " ^ (saturate thy b "b")
--- a/src/HOL/Complex_Main.thy	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Complex_Main.thy	Wed Dec 01 15:38:05 2010 +0100
@@ -10,6 +10,9 @@
   Ln
   Taylor
   Deriv
+uses "~~/src/Tools/subtyping.ML"
 begin
 
+setup Subtyping.setup
+
 end
--- a/src/HOL/HOL.thy	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/HOL.thy	Wed Dec 01 15:38:05 2010 +0100
@@ -1796,9 +1796,8 @@
 setup {*
   Code_Preproc.map_pre (fn simpset =>
     simpset addsimprocs [Simplifier.simproc_global_i @{theory} "equal" [@{term HOL.eq}]
-      (fn thy => fn _ => fn Const (_, T) => case strip_type T
-        of (Type _ :: _, _) => SOME @{thm eq_equal}
-         | _ => NONE)])
+      (fn thy => fn _ =>
+        fn Const (_, Type ("fun", [Type _, _])) => SOME @{thm eq_equal} | _ => NONE)])
 *}
 
 
--- a/src/HOL/HOLCF/Tools/holcf_library.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/HOLCF/Tools/holcf_library.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -83,7 +83,7 @@
 
 fun mk_cabs t =
   let val T = fastype_of t
-  in cabs_const (Term.domain_type T, Term.range_type T) $ t end
+  in cabs_const (Term.dest_funT T) $ t end
 
 (* builds the expression (% v1 v2 .. vn. rhs) *)
 fun lambdas [] rhs = rhs
--- a/src/HOL/Import/proof_kernel.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Import/proof_kernel.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -415,9 +415,6 @@
 
 val mk_var = Free
 
-fun dom_rng (Type("fun",[dom,rng])) = (dom,rng)
-  | dom_rng _ = raise ERR "dom_rng" "Not a functional type"
-
 fun mk_thy_const thy Thy Nam Ty = Const(intern_const_name Thy Nam thy,Ty)
 
 local
@@ -1481,7 +1478,7 @@
                         _ $ (Const(@{const_name HOL.eq},_) $ x $ y) => (x,y)
                       | _ => raise ERR "mk_COMB" "Second theorem not an equality"
         val fty = type_of f
-        val (fd,fr) = dom_rng fty
+        val (fd,fr) = Term.dest_funT fty
         val comb_thm' = Drule.instantiate'
                             [SOME (ctyp_of thy fd),SOME (ctyp_of thy fr)]
                             [SOME (cterm_of thy f),SOME (cterm_of thy g),
@@ -1789,7 +1786,7 @@
         val (f,g) = case concl_of th1 of
                         _ $ (Const(@{const_name HOL.eq},_) $ f $ g) => (Term.lambda v f,Term.lambda v g)
                       | _ => raise ERR "mk_ABS" "Bad conclusion"
-        val (fd,fr) = dom_rng (type_of f)
+        val (fd,fr) = Term.dest_funT (type_of f)
         val abs_thm' = Drule.instantiate' [SOME (ctyp_of thy fd), SOME (ctyp_of thy fr)] [SOME (cterm_of thy f), SOME (cterm_of thy g)] abs_thm
         val th2 = Thm.forall_intr cv th1
         val th3 = th2 COMP abs_thm'
@@ -1835,7 +1832,7 @@
                 in
                     fold_rev (fn v => fn th =>
                               let
-                                  val cdom = fst (dom_rng (fst (dom_rng cty)))
+                                  val cdom = fst (Term.dest_funT (fst (Term.dest_funT cty)))
                                   val vty  = type_of v
                                   val newcty = inst_type cdom vty cty
                                   val cc = cterm_of thy (Const(cname,newcty))
@@ -1991,7 +1988,7 @@
                                fun dest_eta_abs (Abs(x,xT,body)) = (x,xT,body)
                                  | dest_eta_abs body =
                                    let
-                                       val (dT,rT) = dom_rng (type_of body)
+                                       val (dT,rT) = Term.dest_funT (type_of body)
                                    in
                                        ("x",dT,body $ Bound 0)
                                    end
--- a/src/HOL/IsaMakefile	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/IsaMakefile	Wed Dec 01 15:38:05 2010 +0100
@@ -385,6 +385,7 @@
 	@$(ISABELLE_TOOL) usedir -b -f main.ML -g true $(OUT)/Pure HOL-Main
 
 HOL_DEPENDENCIES = $(MAIN_DEPENDENCIES) \
+  $(SRC)/Tools/subtyping.ML \
   Archimedean_Field.thy \
   Complex.thy \
   Complex_Main.thy \
@@ -408,9 +409,9 @@
   Series.thy \
   SupInf.thy \
   Taylor.thy \
-  Transcendental.thy \
+  Tools/SMT/smt_real.ML \
   Tools/float_syntax.ML \
-  Tools/SMT/smt_real.ML
+  Transcendental.thy
 
 $(OUT)/HOL: ROOT.ML $(HOL_DEPENDENCIES)
 	@$(ISABELLE_TOOL) usedir -b -g true $(OUT)/Pure HOL
@@ -1030,25 +1031,24 @@
 $(LOG)/HOL-ex.gz: $(OUT)/HOL Decision_Procs/Commutative_Ring.thy	\
   Number_Theory/Primes.thy ex/Abstract_NAT.thy ex/Antiquote.thy		\
   ex/Arith_Examples.thy ex/Arithmetic_Series_Complex.thy ex/BT.thy	\
-  ex/BinEx.thy ex/Binary.thy ex/Birthday_Paradoxon.thy ex/CTL.thy   \
-  ex/Chinese.thy \
-  ex/Classical.thy ex/CodegenSML_Test.thy ex/Coercion_Examples.thy	\
-  ex/Coherent.thy ex/Dedekind_Real.thy ex/Efficient_Nat_examples.thy	\
-  ex/Eval_Examples.thy ex/Fundefs.thy ex/Gauge_Integration.thy		\
-  ex/Groebner_Examples.thy ex/Guess.thy ex/HarmonicSeries.thy		\
-  ex/Hebrew.thy ex/Hex_Bin_Examples.thy ex/Higher_Order_Logic.thy	\
-  ex/Iff_Oracle.thy ex/Induction_Schema.thy ex/InductiveInvariant.thy	\
-  ex/InductiveInvariant_examples.thy ex/Intuitionistic.thy		\
-  ex/Lagrange.thy ex/LocaleTest2.thy ex/MT.thy ex/MergeSort.thy		\
-  ex/Meson_Test.thy ex/MonoidGroup.thy ex/Multiquote.thy ex/NatSum.thy	\
-  ex/Normalization_by_Evaluation.thy ex/Numeral.thy ex/PER.thy		\
-  ex/PresburgerEx.thy ex/Primrec.thy ex/Quickcheck_Examples.thy		\
-  ex/Quickcheck_Lattice_Examples.thy ex/Quicksort.thy ex/ROOT.ML	\
-  ex/Recdefs.thy ex/Records.thy ex/ReflectionEx.thy			\
-  ex/Refute_Examples.thy ex/SAT_Examples.thy ex/SVC_Oracle.thy		\
-  ex/Serbian.thy ex/Sqrt.thy ex/Sqrt_Script.thy ex/Sudoku.thy		\
-  ex/Tarski.thy ex/Termination.thy ex/Transfer_Ex.thy ex/Tree23.thy	\
-  ex/Unification.thy ex/While_Combinator_Example.thy			\
+  ex/BinEx.thy ex/Binary.thy ex/Birthday_Paradoxon.thy ex/CTL.thy	\
+  ex/Chinese.thy ex/Classical.thy ex/CodegenSML_Test.thy		\
+  ex/Coercion_Examples.thy ex/Coherent.thy ex/Dedekind_Real.thy		\
+  ex/Efficient_Nat_examples.thy ex/Eval_Examples.thy ex/Fundefs.thy	\
+  ex/Gauge_Integration.thy ex/Groebner_Examples.thy ex/Guess.thy	\
+  ex/HarmonicSeries.thy ex/Hebrew.thy ex/Hex_Bin_Examples.thy		\
+  ex/Higher_Order_Logic.thy ex/Iff_Oracle.thy ex/Induction_Schema.thy	\
+  ex/InductiveInvariant.thy ex/InductiveInvariant_examples.thy		\
+  ex/Intuitionistic.thy ex/Lagrange.thy ex/LocaleTest2.thy ex/MT.thy	\
+  ex/MergeSort.thy ex/Meson_Test.thy ex/MonoidGroup.thy			\
+  ex/Multiquote.thy ex/NatSum.thy ex/Normalization_by_Evaluation.thy	\
+  ex/Numeral.thy ex/PER.thy ex/PresburgerEx.thy ex/Primrec.thy		\
+  ex/Quickcheck_Examples.thy ex/Quickcheck_Lattice_Examples.thy		\
+  ex/Quicksort.thy ex/ROOT.ML ex/Recdefs.thy ex/Records.thy		\
+  ex/ReflectionEx.thy ex/Refute_Examples.thy ex/SAT_Examples.thy	\
+  ex/SVC_Oracle.thy ex/Serbian.thy ex/Sqrt.thy ex/Sqrt_Script.thy	\
+  ex/Sudoku.thy ex/Tarski.thy ex/Termination.thy ex/Transfer_Ex.thy	\
+  ex/Tree23.thy ex/Unification.thy ex/While_Combinator_Example.thy	\
   ex/document/root.bib ex/document/root.tex ex/set.thy ex/svc_funcs.ML	\
   ex/svc_test.thy
 	@$(ISABELLE_TOOL) usedir $(OUT)/HOL ex
--- a/src/HOL/Nominal/nominal_datatype.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Nominal/nominal_datatype.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -274,7 +274,7 @@
           fun perm_arg (dt, x) =
             let val T = type_of x
             in if is_rec_type dt then
-                let val (Us, _) = strip_type T
+                let val Us = binder_types T
                 in list_abs (map (pair "x") Us,
                   Free (nth perm_names_types' (body_index dt)) $ pi $
                     list_comb (x, map (fn (i, U) =>
--- a/src/HOL/Tools/Datatype/datatype_codegen.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Datatype/datatype_codegen.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -334,14 +334,14 @@
         val t :: ts2 = drop i ts;
         val names = List.foldr OldTerm.add_term_names
           (map (fst o fst o dest_Var) (List.foldr OldTerm.add_term_vars [] ts1)) ts1;
-        val (Ts, dT) = split_last (take (i+1) (fst (strip_type T)));
+        val (Ts, dT) = split_last (take (i+1) (binder_types T));
 
         fun pcase [] [] [] gr = ([], gr)
           | pcase ((cname, cargs)::cs) (t::ts) (U::Us) gr =
               let
                 val j = length cargs;
                 val xs = Name.variant_list names (replicate j "x");
-                val Us' = take j (fst (strip_type U));
+                val Us' = take j (binder_types U);
                 val frees = map2 (curry Free) xs Us';
                 val (cp, gr0) = invoke_codegen thy defs dep module false
                   (list_comb (Const (cname, Us' ---> dT), frees)) gr;
@@ -385,26 +385,33 @@
 
 (* code generators for terms and types *)
 
-fun datatype_codegen thy defs dep module brack t gr = (case strip_comb t of
-   (c as Const (s, T), ts) =>
-     (case Datatype_Data.info_of_case thy s of
+fun datatype_codegen thy defs dep module brack t gr =
+  (case strip_comb t of
+    (c as Const (s, T), ts) =>
+      (case Datatype_Data.info_of_case thy s of
         SOME {index, descr, ...} =>
-          if is_some (get_assoc_code thy (s, T)) then NONE else
-          SOME (pretty_case thy defs dep module brack
-            (#3 (the (AList.lookup op = descr index))) c ts gr )
-      | NONE => case (Datatype_Data.info_of_constr thy (s, T), strip_type T) of
-        (SOME {index, descr, ...}, (_, U as Type (tyname, _))) =>
-          if is_some (get_assoc_code thy (s, T)) then NONE else
-          let
-            val SOME (tyname', _, constrs) = AList.lookup op = descr index;
-            val SOME args = AList.lookup op = constrs s
-          in
-            if tyname <> tyname' then NONE
-            else SOME (pretty_constr thy defs
-              dep module brack args c ts (snd (invoke_tycodegen thy defs dep module false U gr)))
-          end
-      | _ => NONE)
- | _ => NONE);
+          if is_some (get_assoc_code thy (s, T)) then NONE
+          else
+            SOME (pretty_case thy defs dep module brack
+              (#3 (the (AList.lookup op = descr index))) c ts gr)
+      | NONE =>
+          (case (Datatype_Data.info_of_constr thy (s, T), body_type T) of
+            (SOME {index, descr, ...}, U as Type (tyname, _)) =>
+              if is_some (get_assoc_code thy (s, T)) then NONE
+              else
+                let
+                  val SOME (tyname', _, constrs) = AList.lookup op = descr index;
+                  val SOME args = AList.lookup op = constrs s;
+                in
+                  if tyname <> tyname' then NONE
+                  else
+                    SOME
+                      (pretty_constr thy defs
+                        dep module brack args c ts
+                        (snd (invoke_tycodegen thy defs dep module false U gr)))
+                end
+          | _ => NONE))
+  | _ => NONE);
 
 fun datatype_tycodegen thy defs dep module brack (Type (s, Ts)) gr =
       (case Datatype_Data.get_info thy s of
--- a/src/HOL/Tools/Datatype/datatype_data.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Datatype/datatype_data.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -72,7 +72,7 @@
 fun info_of_constr thy (c, T) =
   let
     val tab = Symtab.lookup_list ((#constrs o DatatypesData.get) thy) c;
-    val hint = case strip_type T of (_, Type (tyco, _)) => SOME tyco | _ => NONE;
+    val hint = case body_type T of Type (tyco, _) => SOME tyco | _ => NONE;
     val default = if null tab then NONE
       else SOME (snd (Library.last_elem tab))
         (*conservative wrt. overloaded constructors*);
@@ -387,7 +387,7 @@
     fun type_of_constr (cT as (_, T)) =
       let
         val frees = OldTerm.typ_tfrees T;
-        val (tyco, vs) = ((apsnd o map) (dest_TFree) o dest_Type o snd o strip_type) T
+        val (tyco, vs) = (apsnd o map) dest_TFree (dest_Type (body_type T))
           handle TYPE _ => no_constr cT
         val _ = if has_duplicates (eq_fst (op =)) vs then no_constr cT else ();
         val _ = if length frees <> length vs then no_constr cT else ();
@@ -412,8 +412,8 @@
       (TFree o (the o AList.lookup (op =) (map fst raw_vs ~~ vs)) o fst o dest_TFree) T);
 
     val cs = map (apsnd (map norm_constr)) raw_cs;
-    val dtyps_of_typ = map (dtyp_of_typ (map (rpair (map fst vs) o fst) cs))
-      o fst o strip_type;
+    val dtyps_of_typ =
+      map (dtyp_of_typ (map (rpair (map fst vs) o fst) cs)) o binder_types;
     val dt_names = map fst cs;
 
     fun mk_spec (i, (tyco, constr)) = (i, (tyco,
--- a/src/HOL/Tools/Datatype/datatype_prop.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Datatype/datatype_prop.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -385,7 +385,7 @@
 
         fun mk_clause ((f, g), (cname, _)) =
           let
-            val (Ts, _) = strip_type (fastype_of f);
+            val Ts = binder_types (fastype_of f);
             val tnames = Name.variant_list used (make_tnames Ts);
             val frees = map Free (tnames ~~ Ts)
           in
--- a/src/HOL/Tools/Datatype/datatype_realizer.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Datatype/datatype_realizer.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -25,7 +25,7 @@
 fun prf_of thm =
   Reconstruct.reconstruct_proof (Thm.theory_of_thm thm) (Thm.prop_of thm) (Thm.proof_of thm);
 
-fun is_unit t = snd (strip_type (fastype_of t)) = HOLogic.unitT;
+fun is_unit t = body_type (fastype_of t) = HOLogic.unitT;
 
 fun tname_of (Type (s, _)) = s
   | tname_of _ = "";
--- a/src/HOL/Tools/Predicate_Compile/predicate_compile_aux.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Predicate_Compile/predicate_compile_aux.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -485,7 +485,7 @@
 
 fun is_pred thy constname = (body_type (Sign.the_const_type thy constname) = HOLogic.boolT);
 
-fun is_predT (T as Type("fun", [_, _])) = (snd (strip_type T) = @{typ bool})
+fun is_predT (T as Type("fun", [_, _])) = (body_type T = @{typ bool})
   | is_predT _ = false
 
 (*** check if a term contains only constructor functions ***)
--- a/src/HOL/Tools/Predicate_Compile/predicate_compile_core.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Predicate_Compile/predicate_compile_core.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -87,17 +87,6 @@
     Const (@{const_name "scomp"}, T --> U --> A --> D) $ t $ u
   end;
 
-fun dest_funT (Type ("fun",[S, T])) = (S, T)
-  | dest_funT T = raise TYPE ("dest_funT", [T], [])
- 
-fun mk_fun_comp (t, u) =
-  let
-    val (_, B) = dest_funT (fastype_of t)
-    val (C, A) = dest_funT (fastype_of u)
-  in
-    Const(@{const_name "Fun.comp"}, (A --> B) --> (C --> A) --> C --> B) $ t $ u
-  end;
-
 fun dest_randomT (Type ("fun", [@{typ Random.seed},
   Type (@{type_name Product_Type.prod}, [Type (@{type_name Product_Type.prod}, [T, @{typ "unit => Code_Evaluation.term"}]) ,@{typ Random.seed}])])) = T
   | dest_randomT T = raise TYPE ("dest_randomT", [T], [])
--- a/src/HOL/Tools/Predicate_Compile/predicate_compile_fun.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Predicate_Compile/predicate_compile_fun.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -81,7 +81,7 @@
 (* TODO: does not work with higher order functions yet *)
 fun mk_rewr_eq (func, pred) =
   let
-    val (argTs, resT) = (strip_type (fastype_of func))
+    val (argTs, resT) = strip_type (fastype_of func)
     val nctxt =
       Name.make_context (Term.fold_aterms (fn Free (x, _) => insert (op =) x | _ => I) (func $ pred) [])
     val (argnames, nctxt') = Name.variants (replicate (length argTs) "a") nctxt
--- a/src/HOL/Tools/Quotient/quotient_tacs.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/Quotient/quotient_tacs.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -234,9 +234,6 @@
     (Abs a) => snd (Term.dest_abs a)
   | _ => unlam (Abs("", domain_type (fastype_of t), (incr_boundvars 1 t) $ (Bound 0)))
 
-fun dest_fun_type (Type("fun", [T, S])) = (T, S)
-  | dest_fun_type _ = error "dest_fun_type"
-
 val bare_concl = HOLogic.dest_Trueprop o Logic.strip_assums_concl
 
 (* We apply apply_rsp only in case if the type needs lifting.
@@ -296,7 +293,7 @@
     | SOME (rel $ _ $ (rep $ (abs $ _))) =>
         let
           val thy = ProofContext.theory_of ctxt;
-          val (ty_a, ty_b) = dest_fun_type (fastype_of abs);
+          val (ty_a, ty_b) = dest_funT (fastype_of abs);
           val ty_inst = map (SOME o (ctyp_of thy)) [ty_a, ty_b];
         in
           case try (map (SOME o (cterm_of thy))) [rel, abs, rep] of
@@ -483,8 +480,8 @@
     (Const (@{const_name map_fun}, _) $ r1 $ a2) $ (Abs _) =>
       let
         val thy = ProofContext.theory_of ctxt
-        val (ty_b, ty_a) = dest_fun_type (fastype_of r1)
-        val (ty_c, ty_d) = dest_fun_type (fastype_of a2)
+        val (ty_b, ty_a) = dest_funT (fastype_of r1)
+        val (ty_c, ty_d) = dest_funT (fastype_of a2)
         val tyinst = map (SOME o (ctyp_of thy)) [ty_a, ty_b, ty_c, ty_d]
         val tinst = [NONE, NONE, SOME (cterm_of thy r1), NONE, SOME (cterm_of thy a2)]
         val thm1 = Drule.instantiate' tyinst tinst @{thm lambda_prs[THEN eq_reflection]}
--- a/src/HOL/Tools/SMT/smt_utils.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/SMT/smt_utils.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -10,7 +10,6 @@
   val repeat_yield: ('a -> 'b -> ('a * 'b) option) -> 'a -> 'b -> 'a * 'b
 
   (* types *)
-  val split_type: typ -> typ * typ
   val dest_funT: int -> typ -> typ list * typ
 
   (* terms *)
@@ -57,8 +56,6 @@
 
 (* types *)
 
-fun split_type T = (Term.domain_type T, Term.range_type T)
-
 val dest_funT =
   let
     fun dest Ts 0 T = (rev Ts, T)
--- a/src/HOL/Tools/SMT/z3_model.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/SMT/z3_model.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -131,7 +131,7 @@
       end)
 
 and trans_array T a =
-  let val (dT, rT) = U.split_type T
+  let val (dT, rT) = Term.dest_funT T
   in
     (case a of
       Fresh e => trans_expr rT e #>> (fn t => Abs ("x", dT, t))
@@ -151,11 +151,11 @@
 
 fun mk_update ([], u) _ = u
   | mk_update ([t], u) f =
-      uncurry mk_fun_upd (U.split_type (Term.fastype_of f)) $ f $ t $ u
+      uncurry mk_fun_upd (Term.dest_funT (Term.fastype_of f)) $ f $ t $ u
   | mk_update (t :: ts, u) f =
       let
-        val (dT, rT) = U.split_type (Term.fastype_of f)
-        val (dT', rT') = U.split_type rT
+        val (dT, rT) = Term.dest_funT (Term.fastype_of f)
+        val (dT', rT') = Term.dest_funT rT
       in
         mk_fun_upd dT rT $ f $ t $
           mk_update (ts, u) (Term.absdummy (dT', Const ("_", rT')))
--- a/src/HOL/Tools/SMT/z3_proof_methods.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/SMT/z3_proof_methods.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -36,14 +36,14 @@
 
 fun mk_inv_of ctxt ct =
   let
-    val (dT, rT) = U.split_type (U.typ_of ct)
+    val (dT, rT) = Term.dest_funT (U.typ_of ct)
     val inv = U.certify ctxt (mk_inv_into dT rT)
     val univ = U.certify ctxt (mk_univ dT)
   in Thm.mk_binop inv univ ct end
 
 fun mk_inj_prop ctxt ct =
   let
-    val (dT, rT) = U.split_type (U.typ_of ct)
+    val (dT, rT) = Term.dest_funT (U.typ_of ct)
     val inj = U.certify ctxt (mk_inj_on dT rT)
     val univ = U.certify ctxt (mk_univ dT)
   in U.mk_cprop (Thm.mk_binop inj ct univ) end
--- a/src/HOL/Tools/hologic.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/hologic.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -8,6 +8,7 @@
 sig
   val typeS: sort
   val typeT: typ
+  val mk_comp: term * term -> term
   val boolN: string
   val boolT: typ
   val Trueprop: term
@@ -142,6 +143,16 @@
 val typeT = Type_Infer.anyT typeS;
 
 
+(* functions *)
+
+fun mk_comp (f, g) =
+  let
+    val fT = fastype_of f;
+    val gT = fastype_of g;
+    val compT = fT --> gT --> domain_type gT --> range_type fT;
+  in Const ("Fun.comp", compT) $ f $ g end;
+
+
 (* bool and set *)
 
 val boolN = "HOL.bool";
--- a/src/HOL/Tools/recfun_codegen.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/recfun_codegen.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -34,7 +34,8 @@
 
 fun avoid_value thy [thm] =
       let val (_, T) = Code.const_typ_eqn thy thm
-      in if null (Term.add_tvarsT T []) orelse (null o fst o strip_type) T
+      in
+        if null (Term.add_tvarsT T []) orelse null (binder_types T)
         then [thm]
         else [Code.expand_eta thy 1 thm]
       end
--- a/src/HOL/Tools/record.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/record.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -1013,18 +1013,9 @@
     SOME u_name => u_name = s
   | NONE => raise TERM ("is_sel_upd_pair: not update", [Const (u, t')]));
 
-fun mk_comp f g =
-  let
-    val X = fastype_of g;
-    val A = domain_type X;
-    val B = range_type X;
-    val C = range_type (fastype_of f);
-    val T = (B --> C) --> (A --> B) --> A --> C;
-  in Const (@{const_name Fun.comp}, T) $ f $ g end;
-
 fun mk_comp_id f =
   let val T = range_type (fastype_of f)
-  in mk_comp (Const (@{const_name Fun.id}, T --> T)) f end;
+  in HOLogic.mk_comp (Const (@{const_name Fun.id}, T --> T), f) end;
 
 fun get_upd_funs (upd $ _ $ t) = upd :: get_upd_funs t
   | get_upd_funs _ = [];
@@ -1037,10 +1028,10 @@
       let
         (* FIXME fresh "f" (!?) *)
         val T = domain_type (fastype_of upd);
-        val lhs = mk_comp acc (upd $ Free ("f", T));
+        val lhs = HOLogic.mk_comp (acc, upd $ Free ("f", T));
         val rhs =
           if is_sel_upd_pair thy acc upd
-          then mk_comp (Free ("f", T)) acc
+          then HOLogic.mk_comp (Free ("f", T), acc)
           else mk_comp_id acc;
         val prop = lhs === rhs;
         val othm =
@@ -1061,11 +1052,11 @@
     (* FIXME fresh "f" (!?) *)
     val f = Free ("f", domain_type (fastype_of u));
     val f' = Free ("f'", domain_type (fastype_of u'));
-    val lhs = mk_comp (u $ f) (u' $ f');
+    val lhs = HOLogic.mk_comp (u $ f, u' $ f');
     val rhs =
       if comp
-      then u $ mk_comp f f'
-      else mk_comp (u' $ f') (u $ f);
+      then u $ HOLogic.mk_comp (f, f')
+      else HOLogic.mk_comp (u' $ f', u $ f);
     val prop = lhs === rhs;
     val othm =
       Goal.prove (ProofContext.init_global thy) [] [] prop
@@ -1870,7 +1861,7 @@
          (fn _ => fn eq_def => tac eq_def) eq_def)
     |-> (fn eq_def => fn thy => thy |> Code.del_eqn eq_def |> Code.add_default_eqn (mk_eq thy eq_def))
     |> (fn thy => Code.add_nbe_default_eqn (mk_eq_refl thy) thy)
-    |> ensure_random_record ext_tyco vs (fst ext) ((fst o strip_type o snd) ext)
+    |> ensure_random_record ext_tyco vs (fst ext) (binder_types (snd ext))
   end;
 
 
--- a/src/HOL/Tools/smallvalue_generators.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/Tools/smallvalue_generators.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -18,17 +18,6 @@
 
 (** general term functions **)
 
-fun dest_funT (Type ("fun",[S, T])) = (S, T)
-  | dest_funT T = raise TYPE ("dest_funT", [T], [])
- 
-fun mk_fun_comp (t, u) =
-  let
-    val (_, B) = dest_funT (fastype_of t)
-    val (C, A) = dest_funT (fastype_of u)
-  in
-    Const(@{const_name "Fun.comp"}, (A --> B) --> (C --> A) --> C --> B) $ t $ u
-  end;
-
 fun mk_measure f =
   let
     val Type ("fun", [T, @{typ nat}]) = fastype_of f 
@@ -139,7 +128,7 @@
   let
     val _ = Datatype_Aux.message config "Creating smallvalue generators ...";
     val eqs = mk_equations thy descr vs tycos (names, auxnames) (Ts, Us)
-    fun mk_single_measure T = mk_fun_comp (@{term "Code_Numeral.nat_of"},
+    fun mk_single_measure T = HOLogic.mk_comp (@{term "Code_Numeral.nat_of"},
       Const (@{const_name "Product_Type.snd"}, T --> @{typ "code_numeral"}))
     fun mk_termination_measure T =
       let
--- a/src/HOL/ex/Coercion_Examples.thy	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/HOL/ex/Coercion_Examples.thy	Wed Dec 01 15:38:05 2010 +0100
@@ -5,12 +5,9 @@
 *)
 
 theory Coercion_Examples
-imports Main
-uses "~~/src/Tools/subtyping.ML"
+imports Complex_Main
 begin
 
-setup Subtyping.setup
-
 (* Error messages test *)
 
 consts func :: "(nat \<Rightarrow> int) \<Rightarrow> nat"
--- a/src/Pure/Isar/code.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Pure/Isar/code.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -358,7 +358,7 @@
  of SOME ty => ty
   | NONE => (Type.strip_sorts o Sign.the_const_type thy) c;
 
-fun args_number thy = length o fst o strip_type o const_typ thy;
+fun args_number thy = length o binder_types o const_typ thy;
 
 fun subst_signature thy c ty =
   let
@@ -391,7 +391,7 @@
     fun last_typ c_ty ty =
       let
         val tfrees = Term.add_tfreesT ty [];
-        val (tyco, vs) = ((apsnd o map) (dest_TFree) o dest_Type o snd o strip_type) ty
+        val (tyco, vs) = (apsnd o map) dest_TFree (dest_Type (body_type ty))
           handle TYPE _ => no_constr thy "bad type" c_ty
         val _ = if tyco = "fun" then no_constr thy "bad type" c_ty else ();
         val _ = if has_duplicates (eq_fst (op =)) vs
@@ -420,7 +420,7 @@
         val the_v = the o AList.lookup (op =) (vs ~~ vs');
         val ty' = map_type_tfree (fn (v, _) => TFree (the_v v)) ty;
         val (vs'', _) = logical_typscheme thy (c, ty');
-      in (c, (vs'', (fst o strip_type) ty')) end;
+      in (c, (vs'', binder_types ty')) end;
     val c' :: cs' = map (analyze_constructor thy) cs;
     val ((tyco, sorts), cs'') = fold add cs' (apsnd single c');
     val vs = Name.names Name.context Name.aT sorts;
@@ -444,7 +444,7 @@
   | _ => error ("Not an abstract type: " ^ tyco);
  
 fun get_type_of_constr_or_abstr thy c =
-  case (snd o strip_type o const_typ thy) c
+  case (body_type o const_typ thy) c
    of Type (tyco, _) => let val ((_, cos), abstract) = get_type thy tyco
         in if member (op =) (map fst cos) c then SOME (tyco, abstract) else NONE end
     | _ => NONE;
@@ -517,7 +517,7 @@
       | check n (Const (c_ty as (c, ty))) =
           if allow_pats then let
             val c' = AxClass.unoverload_const thy c_ty
-          in if n = (length o fst o strip_type o subst_signature thy c') ty
+          in if n = (length o binder_types o subst_signature thy c') ty
             then if allow_consts orelse is_constr thy c'
               then ()
               else bad (quote c ^ " is not a constructor, on left hand side of equation")
@@ -1139,7 +1139,7 @@
     val (zs, _) = Name.variants (replicate (num_args - 1) "") ctxt;
     val (ws, vs) = chop pos zs;
     val T = Logic.unvarifyT_global (Sign.the_const_type thy case_const);
-    val Ts = (fst o strip_type) T;
+    val Ts = binder_types T;
     val T_cong = nth Ts pos;
     fun mk_prem z = Free (z, T_cong);
     fun mk_concl z = list_comb (Const (case_const, T), map2 (curry Free) (ws @ z :: vs) Ts);
--- a/src/Pure/Proof/extraction.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Pure/Proof/extraction.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -135,11 +135,13 @@
 
 val prf_subst_TVars = Proofterm.map_proof_types o typ_subst_TVars;
 
-fun relevant_vars types prop = List.foldr (fn
-      (Var ((a, _), T), vs) => (case strip_type T of
-        (_, Type (s, _)) => if member (op =) types s then a :: vs else vs
-      | _ => vs)
-    | (_, vs) => vs) [] (vars_of prop);
+fun relevant_vars types prop =
+  List.foldr
+    (fn (Var ((a, _), T), vs) =>
+        (case body_type T of
+          Type (s, _) => if member (op =) types s then a :: vs else vs
+        | _ => vs)
+      | (_, vs) => vs) [] (vars_of prop);
 
 fun tname_of (Type (s, _)) = s
   | tname_of _ = "";
--- a/src/Pure/codegen.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Pure/codegen.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -664,7 +664,7 @@
                  NONE =>
                    let
                      val _ = message ("expanding definition of " ^ s);
-                     val (Ts, _) = strip_type U;
+                     val Ts = binder_types U;
                      val (args', rhs') =
                        if not (null args) orelse null Ts then (args, rhs) else
                          let val v = Free (new_name rhs "x", hd Ts)
--- a/src/Pure/term.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Pure/term.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -48,6 +48,7 @@
   val dest_comb: term -> term * term
   val domain_type: typ -> typ
   val range_type: typ -> typ
+  val dest_funT: typ -> typ * typ
   val binder_types: typ -> typ list
   val body_type: typ -> typ
   val strip_type: typ -> typ list * typ
@@ -283,20 +284,24 @@
   | dest_comb t = raise TERM("dest_comb", [t]);
 
 
-fun domain_type (Type("fun", [T,_])) = T
-and range_type  (Type("fun", [_,T])) = T;
+fun domain_type (Type ("fun", [T, _])) = T;
+
+fun range_type (Type ("fun", [_, U])) = U;
+
+fun dest_funT (Type ("fun", [T, U])) = (T, U)
+  | dest_funT T = raise TYPE ("dest_funT", [T], []);
+
 
 (* maps  [T1,...,Tn]--->T  to the list  [T1,T2,...,Tn]*)
-fun binder_types (Type("fun",[S,T])) = S :: binder_types T
-  | binder_types _   =  [];
+fun binder_types (Type ("fun", [T, U])) = T :: binder_types U
+  | binder_types _ = [];
 
 (* maps  [T1,...,Tn]--->T  to T*)
-fun body_type (Type("fun",[S,T])) = body_type T
-  | body_type T   =  T;
+fun body_type (Type ("fun", [_, U])) = body_type U
+  | body_type T = T;
 
 (* maps  [T1,...,Tn]--->T  to   ([T1,T2,...,Tn], T)  *)
-fun strip_type T : typ list * typ =
-  (binder_types T, body_type T);
+fun strip_type T = (binder_types T, body_type T);
 
 
 (*Compute the type of the term, checking that combinations are well-typed
@@ -707,7 +712,7 @@
             val (vs, t') = expand_eta Ts (t $ Free (v, T)) used';
           in ((v, T) :: vs, t') end;
     val ((vs1, t'), (k', used')) = strip_abs t (k, used);
-    val Ts = (fst o chop k' o fst o strip_type o fastype_of) t';
+    val Ts = fst (chop k' (binder_types (fastype_of t')));
     val (vs2, t'') = expand_eta Ts t' used';
   in (vs1 @ vs2, t'') end;
 
@@ -1002,5 +1007,5 @@
 
 end;
 
-structure BasicTerm: BASIC_TERM = Term;
-open BasicTerm;
+structure Basic_Term: BASIC_TERM = Term;
+open Basic_Term;
--- a/src/Tools/Code/code_thingol.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Tools/Code/code_thingol.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -710,7 +710,7 @@
       else ()
     val arg_typs = Sign.const_typargs thy (c, ty);
     val sorts = Code_Preproc.sortargs eqngr c;
-    val function_typs = (fst o Term.strip_type) ty;
+    val function_typs = Term.binder_types ty;
   in
     ensure_const thy algbr eqngr permissive c
     ##>> fold_map (translate_typ thy algbr eqngr permissive) arg_typs
@@ -724,7 +724,7 @@
   #>> (fn (t, ts) => t `$$ ts)
 and translate_case thy algbr eqngr permissive some_thm (num_args, (t_pos, case_pats)) (c_ty, ts) =
   let
-    fun arg_types num_args ty = (fst o chop num_args o fst o strip_type) ty;
+    fun arg_types num_args ty = fst (chop num_args (binder_types ty));
     val tys = arg_types num_args (snd c_ty);
     val ty = nth tys t_pos;
     fun mk_constr c t = let val n = Code.args_number thy c
--- a/src/Tools/subtyping.ML	Wed Dec 01 11:45:37 2010 +0100
+++ b/src/Tools/subtyping.ML	Wed Dec 01 15:38:05 2010 +0100
@@ -11,6 +11,7 @@
     term list -> term list
   val add_type_map: term -> Context.generic -> Context.generic
   val add_coercion: term -> Context.generic -> Context.generic
+  val gen_coercion: Proof.context -> typ Vartab.table -> (typ * typ) -> term
   val setup: theory -> theory
 end;
 
@@ -86,8 +87,9 @@
 val is_fixedvarT = fn (TVar (xi, _)) => not (Type_Infer.is_param xi) | _ => false;
 
 
-(* unification *)  (* TODO dup? needed for weak unification *)
+(* unification *)
 
+exception TYPE_INFERENCE_ERROR of unit -> string;
 exception NO_UNIFIER of string * typ Vartab.table;
 
 fun unify weak ctxt =
@@ -185,6 +187,10 @@
 
 (** error messages **)
 
+fun gen_msg err msg = 
+  err () ^ "\nNow trying to infer coercions:\n\nCoercion inference failed" ^ 
+  (if msg = "" then "" else ": " ^ msg) ^ "\n";
+
 fun prep_output ctxt tye bs ts Ts =
   let
     val (Ts_bTs', ts') = Type_Infer.finish ctxt tye (Ts @ map snd bs, ts);
@@ -195,23 +201,23 @@
   in (map prep ts', Ts') end;
 
 fun err_loose i = error ("Loose bound variable: B." ^ string_of_int i);
-
-fun inf_failed msg =
-  "Subtype inference failed" ^ (if msg = "" then "" else ": " ^ msg) ^ "\n\n";
+  
+fun unif_failed msg =
+  "Type unification failed" ^ (if msg = "" then "" else ": " ^ msg) ^ "\n\n";
 
-fun err_appl ctxt msg tye bs t T u U =
+fun subtyping_err_appl_msg ctxt msg tye bs t T u U () =
   let val ([t', u'], [T', U']) = prep_output ctxt tye bs [t, u] [T, U]
-  in error (inf_failed msg ^ Type.appl_error (Syntax.pp ctxt) t' T' u' U' ^ "\n") end;
-
-fun err_subtype ctxt msg tye (bs, t $ u, U, V, U') =
-  err_appl ctxt msg tye bs t (U --> V) u U';
+  in msg ^ Type.appl_error (Syntax.pp ctxt) t' T' u' U' ^ "\n" end;
+  
+fun err_appl_msg ctxt msg tye bs t T u U () =
+  let val ([t', u'], [T', U']) = prep_output ctxt tye bs [t, u] [T, U]
+  in unif_failed msg ^ Type.appl_error (Syntax.pp ctxt) t' T' u' U' ^ "\n" end;
 
 fun err_list ctxt msg tye Ts =
   let
     val (_, Ts') = prep_output ctxt tye [] [] Ts;
-    val text = cat_lines ([inf_failed msg,
-      "Cannot unify a list of types that should be the same,",
-      "according to suptype dependencies:",
+    val text = cat_lines ([msg,
+      "Cannot unify a list of types that should be the same:",
       (Pretty.string_of (Pretty.list "[" "]" (map (Pretty.typ (Syntax.pp ctxt)) Ts')))]);
   in
     error text
@@ -222,15 +228,15 @@
     val pp = Syntax.pp ctxt;
     val (ts, Ts) = fold
       (fn (bs, t $ u, U, _, U') => fn (ts, Ts) =>
-        let val (t', T') = prep_output ctxt tye bs [t, u] [U, U']
+        let val (t', T') = prep_output ctxt tye bs [t, u] [U', U]
         in (t' :: ts, T' :: Ts) end)
       packs ([], []);
-    val text = cat_lines ([inf_failed msg, "Cannot fullfill subtype constraints:"] @
+    val text = cat_lines ([msg, "Cannot fulfil subtype constraints:"] @
         (map2 (fn [t, u] => fn [T, U] => Pretty.string_of (
           Pretty.block [
             Pretty.typ pp T, Pretty.brk 2, Pretty.str "<:", Pretty.brk 2, Pretty.typ pp U,
             Pretty.brk 3, Pretty.str "from function application", Pretty.brk 2,
-            Pretty.block [Pretty.term pp t, Pretty.brk 1, Pretty.term pp u]]))
+            Pretty.block [Pretty.term pp (t $ u)]]))
         ts Ts))
   in
     error text
@@ -240,7 +246,7 @@
 
 (** constraint generation **)
 
-fun generate_constraints ctxt =
+fun generate_constraints ctxt err =
   let
     fun gen cs _ (Const (_, T)) tye_idx = (T, tye_idx, cs)
       | gen cs _ (Free (_, T)) tye_idx = (T, tye_idx, cs)
@@ -257,7 +263,7 @@
             val U = Type_Infer.mk_param idx [];
             val V = Type_Infer.mk_param (idx + 1) [];
             val tye_idx''= strong_unify ctxt (U --> V, T) (tye, idx + 2)
-              handle NO_UNIFIER (msg, tye') => err_appl ctxt msg tye' bs t T u U;
+              handle NO_UNIFIER (msg, tye') => error (gen_msg err msg);
             val error_pack = (bs, t $ u, U, V, U');
           in (V, tye_idx'', ((U', U), error_pack) :: cs'') end;
   in
@@ -270,7 +276,7 @@
 
 exception BOUND_ERROR of string;
 
-fun process_constraints ctxt cs tye_idx =
+fun process_constraints ctxt err cs tye_idx =
   let
     val coes_graph = coes_graph_of ctxt;
     val tmaps = tmaps_of ctxt;
@@ -289,9 +295,8 @@
     (* check whether constraint simplification will terminate using weak unification *)
 
     val _ = fold (fn (TU, error_pack) => fn tye_idx =>
-      (weak_unify ctxt TU tye_idx handle NO_UNIFIER (msg, tye) =>
-        err_subtype ctxt ("Weak unification of subtype constraints fails:\n" ^ msg)
-          tye error_pack)) cs tye_idx;
+      weak_unify ctxt TU tye_idx handle NO_UNIFIER (msg, tye) =>
+        error (gen_msg err ("weak unification of subtype constraints fails\n" ^ msg))) cs tye_idx;
 
 
     (* simplify constraints *)
@@ -310,7 +315,8 @@
                 COVARIANT => (constraint :: cs, tye_idx)
               | CONTRAVARIANT => (swap constraint :: cs, tye_idx)
               | INVARIANT => (cs, strong_unify ctxt constraint tye_idx
-                  handle NO_UNIFIER (msg, tye) => err_subtype ctxt msg tye error_pack));
+                  handle NO_UNIFIER (msg, tye) => 
+                    error (gen_msg err ("failed to unify invariant arguments\n" ^ msg))));
             val (new, (tye', idx')) = apfst (fn cs => (cs ~~ replicate (length cs) error_pack))
               (fold new_constraints (arg_var ~~ (Ts ~~ Us)) ([], (tye, idx)));
             val test_update = is_compT orf is_freeT orf is_fixedvarT;
@@ -348,7 +354,7 @@
           in
             if subsort (S', S) (*TODO check this*)
             then simplify done' todo' (tye', idx)
-            else err_subtype ctxt "Sort mismatch" tye error_pack
+            else error (gen_msg err "sort mismatch")
           end
         and simplify done [] tye_idx = (done, tye_idx)
           | simplify done (((T, U), error_pack) :: todo) (tye_idx as (tye, idx)) =
@@ -356,9 +362,10 @@
                 (Type (a, []), Type (b, [])) =>
                   if a = b then simplify done todo tye_idx
                   else if Graph.is_edge coes_graph (a, b) then simplify done todo tye_idx
-                  else err_subtype ctxt (a ^ " is not a subtype of " ^ b) (fst tye_idx) error_pack
+                  else error (gen_msg err (a ^ " is not a subtype of " ^ b))
               | (Type (a, Ts), Type (b, Us)) =>
-                  if a <> b then err_subtype ctxt "Different constructors" (fst tye_idx) error_pack
+                  if a <> b then error (gen_msg err "different constructors")
+                    (fst tye_idx) error_pack
                   else contract a Ts Us error_pack done todo tye idx
               | (TVar (xi, S), Type (a, Ts as (_ :: _))) =>
                   expand true xi S a Ts error_pack done todo tye idx
@@ -370,8 +377,7 @@
                     exists Type_Infer.is_paramT [T, U]
                   then eliminate [T, U] error_pack done todo tye idx
                   else if exists (is_freeT orf is_fixedvarT) [T, U]
-                  then err_subtype ctxt "Not eliminated free/fixed variables"
-                        (fst tye_idx) error_pack
+                  then error (gen_msg err "not eliminated free/fixed variables")
                   else simplify (((T, U), error_pack) :: done) todo tye_idx);
       in
         simplify [] cs tye_idx
@@ -381,14 +387,22 @@
     (* do simplification *)
 
     val (cs', tye_idx') = simplify_constraints cs tye_idx;
-
-    fun find_error_pack lower T' =
-      map snd (filter (fn ((T, U), _) => if lower then T' = U else T' = T) cs');
+    
+    fun find_error_pack lower T' = map_filter 
+      (fn ((T, U), pack) => if if lower then T' = U else T' = T then SOME pack else NONE) cs';
+      
+    fun find_cycle_packs nodes = 
+      let
+        val (but_last, last) = split_last nodes
+        val pairs = (last, hd nodes) :: (but_last ~~ tl nodes);
+      in
+        map_filter
+          (fn (TU, pack) => if member (op =) pairs TU then SOME pack else NONE)
+          cs'
+      end;
 
     fun unify_list (T :: Ts) tye_idx =
-      fold (fn U => fn tye_idx => strong_unify ctxt (T, U) tye_idx
-        handle NO_UNIFIER (msg, tye) => err_list ctxt msg tye (T :: Ts))
-      Ts tye_idx;
+      fold (fn U => fn tye_idx' => strong_unify ctxt (T, U) tye_idx') Ts tye_idx;
 
     (*styps stands either for supertypes or for subtypes of a type T
       in terms of the subtype-relation (excluding T itself)*)
@@ -403,7 +417,7 @@
           | extract T (U :: Us) =
               if Graph.is_edge coes_graph (adjust T U) then extract T Us
               else if Graph.is_edge coes_graph (adjust U T) then extract U Us
-              else raise BOUND_ERROR "Uncomparable types in type list";
+              else raise BOUND_ERROR "uncomparable types in type list";
       in
         t_of (extract T Ts)
       end;
@@ -435,7 +449,7 @@
         fun candidates T = inter (op =) (filter restriction (T :: styps sup T));
       in
         (case fold candidates Ts (filter restriction (T :: styps sup T)) of
-          [] => raise BOUND_ERROR ("No " ^ (if sup then "supremum" else "infimum"))
+          [] => raise BOUND_ERROR ("no " ^ (if sup then "supremum" else "infimum"))
         | [T] => t_of T
         | Ts => minmax sup Ts)
       end;
@@ -449,23 +463,45 @@
             val (G'', tye_idx') = (add_edge (T, U) G', tye_idx)
               handle Typ_Graph.CYCLES cycles =>
                 let
-                  val (tye, idx) = fold unify_list cycles tye_idx
+                  val (tye, idx) = 
+                    fold 
+                      (fn cycle => fn tye_idx' => (unify_list cycle tye_idx'
+                        handle NO_UNIFIER (msg, tye) => 
+                          err_bound ctxt 
+                            (gen_msg err ("constraint cycle not unifiable" ^ msg)) (fst tye_idx)
+                            (find_cycle_packs cycle)))
+                      cycles tye_idx
                 in
-                  (*all cycles collapse to one node,
-                    because all of them share at least the nodes x and y*)
-                  collapse (tye, idx) (distinct (op =) (flat cycles)) G
-                end;
+                  collapse (tye, idx) cycles G
+                end
           in
             build_graph G'' cs tye_idx'
           end
-    and collapse (tye, idx) nodes G = (*nodes non-empty list*)
+    and collapse (tye, idx) cycles G = (*nodes non-empty list*)
       let
-        val T = hd nodes;
+        (*all cycles collapse to one node,
+          because all of them share at least the nodes x and y*)
+        val nodes = (distinct (op =) (flat cycles));
+        val T = Type_Infer.deref tye (hd nodes);
         val P = new_imm_preds G nodes;
         val S = new_imm_succs G nodes;
         val G' = Typ_Graph.del_nodes (tl nodes) G;
+        fun check_and_gen super T' =
+          let val U = Type_Infer.deref tye T';
+          in
+            if not (is_typeT T) orelse not (is_typeT U) orelse T = U
+            then if super then (hd nodes, T') else (T', hd nodes)
+            else 
+              if super andalso 
+                Graph.is_edge coes_graph (nameT T, nameT U) then (hd nodes, T')
+              else if not super andalso 
+                Graph.is_edge coes_graph (nameT U, nameT T) then (T', hd nodes)
+              else err_bound ctxt (gen_msg err "cycle elimination produces inconsistent graph")
+                    (fst tye_idx) 
+                    (maps find_cycle_packs cycles @ find_error_pack super T')
+          end;
       in
-        build_graph G' (map (fn x => (x, T)) P @ map (fn x => (T, x)) S) (tye, idx)
+        build_graph G' (map (check_and_gen false) P @ map (check_and_gen true) S) (tye, idx)
       end;
 
     fun assign_bound lower G key (tye_idx as (tye, _)) =
@@ -488,7 +524,8 @@
           val assignment =
             if null bound orelse null not_params then NONE
             else SOME (tightest lower S styps_and_sorts (map nameT not_params)
-                handle BOUND_ERROR msg => err_bound ctxt msg tye (find_error_pack lower key))
+                handle BOUND_ERROR msg => 
+                  err_bound ctxt (gen_msg err msg) tye (find_error_pack lower key))
         in
           (case assignment of
             NONE => tye_idx
@@ -501,9 +538,9 @@
                 in
                   if subset (op = o apfst nameT) (filter is_typeT other_bound, s :: styps true s)
                   then apfst (Vartab.update (xi, T)) tye_idx
-                  else err_bound ctxt ("Assigned simple type " ^ s ^
+                  else err_bound ctxt (gen_msg err ("assigned simple type " ^ s ^
                     " clashes with the upper bound of variable " ^
-                    Syntax.string_of_typ ctxt (TVar(xi, S))) tye (find_error_pack (not lower) key)
+                    Syntax.string_of_typ ctxt (TVar(xi, S)))) tye (find_error_pack (not lower) key)
                 end
               else apfst (Vartab.update (xi, T)) tye_idx)
         end
@@ -519,7 +556,8 @@
           val (tye_idx' as (tye, _)) = fold (assign_lb G) ts tye_idx
             |> fold (assign_ub G) ts;
         in
-          assign_alternating ts (filter (Type_Infer.is_paramT o Type_Infer.deref tye) ts) G tye_idx'
+          assign_alternating ts 
+            (filter (Type_Infer.is_paramT o Type_Infer.deref tye) ts) G tye_idx'
         end;
 
     (*Unify all weakly connected components of the constraint forest,
@@ -531,7 +569,10 @@
           filter (Type_Infer.is_paramT o Type_Infer.deref tye) (Typ_Graph.maximals G);
         val to_unify = map (fn T => T :: get_preds G T) max_params;
       in
-        fold unify_list to_unify tye_idx
+        fold 
+          (fn Ts => fn tye_idx' => unify_list Ts tye_idx'
+            handle NO_UNIFIER (msg, tye) => err_list ctxt (gen_msg err msg) (fst tye_idx) Ts)
+          to_unify tye_idx
       end;
 
     fun solve_constraints G tye_idx = tye_idx
@@ -546,77 +587,73 @@
 
 (** coercion insertion **)
 
+fun gen_coercion ctxt tye (T1, T2) =
+  (case pairself (Type_Infer.deref tye) (T1, T2) of
+    ((Type (a, [])), (Type (b, []))) =>
+        if a = b
+        then Abs (Name.uu, Type (a, []), Bound 0)
+        else
+          (case Symreltab.lookup (coes_of ctxt) (a, b) of
+            NONE => raise Fail (a ^ " is not a subtype of " ^ b)
+          | SOME co => co)
+  | ((Type (a, Ts)), (Type (b, Us))) =>
+        if a <> b
+        then raise Fail ("Different constructors: " ^ a ^ " and " ^ b)
+        else
+          let
+            fun inst t Ts =
+              Term.subst_vars
+                (((Term.add_tvar_namesT (fastype_of t) []) ~~ rev Ts), []) t;
+            fun sub_co (COVARIANT, TU) = gen_coercion ctxt tye TU
+              | sub_co (CONTRAVARIANT, TU) = gen_coercion ctxt tye (swap TU);
+            fun ts_of [] = []
+              | ts_of (Type ("fun", [x1, x2]) :: xs) = x1 :: x2 :: (ts_of xs);
+          in
+            (case Symtab.lookup (tmaps_of ctxt) a of
+              NONE => raise Fail ("No map function for " ^ a ^ " known")
+            | SOME tmap =>
+                let
+                  val used_coes = map sub_co ((snd tmap) ~~ (Ts ~~ Us));
+                in
+                  Term.list_comb
+                    (inst (fst tmap) (ts_of (map fastype_of used_coes)), used_coes)
+                end)
+          end
+  | (T, U) =>
+        if Type.could_unify (T, U)
+        then Abs (Name.uu, T, Bound 0)
+        else raise Fail ("Cannot generate coercion from "
+          ^ Syntax.string_of_typ ctxt T ^ " to " ^ Syntax.string_of_typ ctxt U));
+
 fun insert_coercions ctxt tye ts =
   let
-    fun deep_deref T =
-      (case Type_Infer.deref tye T of
-        Type (a, Ts) => Type (a, map deep_deref Ts)
-      | U => U);
-
-    fun gen_coercion ((Type (a, [])), (Type (b, []))) =
-          if a = b
-          then Abs (Name.uu, Type (a, []), Bound 0)
-          else
-            (case Symreltab.lookup (coes_of ctxt) (a, b) of
-              NONE => raise Fail (a ^ " is not a subtype of " ^ b)
-            | SOME co => co)
-      | gen_coercion ((Type (a, Ts)), (Type (b, Us))) =
-          if a <> b
-          then raise raise Fail ("Different constructors: " ^ a ^ " and " ^ b)
-          else
-            let
-              fun inst t Ts =
-                Term.subst_vars
-                  (((Term.add_tvar_namesT (fastype_of t) []) ~~ rev Ts), []) t;
-              fun sub_co (COVARIANT, TU) = gen_coercion TU
-                | sub_co (CONTRAVARIANT, TU) = gen_coercion (swap TU);
-              fun ts_of [] = []
-                | ts_of (Type ("fun", [x1, x2]) :: xs) = x1 :: x2 :: (ts_of xs);
-            in
-              (case Symtab.lookup (tmaps_of ctxt) a of
-                NONE => raise Fail ("No map function for " ^ a ^ " known")
-              | SOME tmap =>
-                  let
-                    val used_coes = map sub_co ((snd tmap) ~~ (Ts ~~ Us));
-                  in
-                    Term.list_comb
-                      (inst (fst tmap) (ts_of (map fastype_of used_coes)), used_coes)
-                  end)
-            end
-      | gen_coercion (T, U) =
-          if Type.could_unify (T, U)
-          then Abs (Name.uu, T, Bound 0)
-          else raise Fail ("Cannot generate coercion from "
-            ^ Syntax.string_of_typ ctxt T ^ " to " ^ Syntax.string_of_typ ctxt U);
-
     fun insert _ (Const (c, T)) =
-          let val T' = deep_deref T;
+          let val T' = T;
           in (Const (c, T'), T') end
       | insert _ (Free (x, T)) =
-          let val T' = deep_deref T;
+          let val T' = T;
           in (Free (x, T'), T') end
       | insert _ (Var (xi, T)) =
-          let val T' = deep_deref T;
+          let val T' = T;
           in (Var (xi, T'), T') end
       | insert bs (Bound i) =
-          let val T = nth bs i handle Subscript =>
-            raise TYPE ("Loose bound variable: B." ^ string_of_int i, [], []);
+          let val T = nth bs i handle Subscript => err_loose i;
           in (Bound i, T) end
       | insert bs (Abs (x, T, t)) =
           let
-            val T' = deep_deref T;
+            val T' = T;
             val (t', T'') = insert (T' :: bs) t;
           in
             (Abs (x, T', t'), T' --> T'')
           end
       | insert bs (t $ u) =
           let
-            val (t', Type ("fun", [U, T])) = insert bs t;
+            val (t', Type ("fun", [U, T])) = apsnd (Type_Infer.deref tye) (insert bs t);
             val (u', U') = insert bs u;
           in
-            if U <> U'
-            then (t' $ (gen_coercion (U', U) $ u'), T)
-            else (t' $ u', T)
+            if can (fn TU => strong_unify ctxt TU (tye, 0)) (U, U')
+            then (t' $ u', T)
+            else (t' $ (gen_coercion ctxt tye (U', U) $ u'), T)
           end
   in
     map (fst o insert []) ts
@@ -630,14 +667,40 @@
   let
     val (idx, ts) = Type_Infer.prepare ctxt const_type var_type raw_ts;
 
-    fun gen_all t (tye_idx, constraints) =
-      let
-        val (_, tye_idx', constraints') = generate_constraints ctxt t tye_idx
-      in (tye_idx', constraints' @ constraints) end;
+    fun inf _ (t as (Const (_, T))) tye_idx = (t, T, tye_idx)
+      | inf _ (t as (Free (_, T))) tye_idx = (t, T, tye_idx)
+      | inf _ (t as (Var (_, T))) tye_idx = (t, T, tye_idx)
+      | inf bs (t as (Bound i)) tye_idx =
+          (t, snd (nth bs i handle Subscript => err_loose i), tye_idx)
+      | inf bs (Abs (x, T, t)) tye_idx =
+          let val (t', U, tye_idx') = inf ((x, T) :: bs) t tye_idx
+          in (Abs (x, T, t'), T --> U, tye_idx') end
+      | inf bs (t $ u) tye_idx =
+          let
+            val (t', T, tye_idx') = inf bs t tye_idx;
+            val (u', U, (tye, idx)) = inf bs u tye_idx';
+            val V = Type_Infer.mk_param idx [];
+            val (tu, tye_idx'') = (t' $ u', strong_unify ctxt (U --> V, T) (tye, idx + 1))
+              handle NO_UNIFIER (msg, tye') => 
+                raise TYPE_INFERENCE_ERROR (err_appl_msg ctxt msg tye' bs t T u U);
+          in (tu, V, tye_idx'') end;
 
-    val (tye_idx, constraints) = fold gen_all ts ((Vartab.empty, idx), []);
-    val (tye, _) = process_constraints ctxt constraints tye_idx;
-    val ts' = insert_coercions ctxt tye ts;
+    fun infer_single t (ts, tye_idx) = 
+      let val (t, _, tye_idx') = inf [] t tye_idx;
+      in (ts @ [t], tye_idx') end;
+      
+    val (ts', (tye, _)) = (fold infer_single ts ([], (Vartab.empty, idx))
+      handle TYPE_INFERENCE_ERROR err =>     
+        let
+          fun gen_single t (tye_idx, constraints) =
+            let val (_, tye_idx', constraints') = generate_constraints ctxt err t tye_idx
+            in (tye_idx', constraints' @ constraints) end;
+      
+          val (tye_idx, constraints) = fold gen_single ts ((Vartab.empty, idx), []);
+          val (tye, idx) = process_constraints ctxt err constraints tye_idx;
+        in 
+          (insert_coercions ctxt tye ts, (tye, idx))
+        end);
 
     val (_, ts'') = Type_Infer.finish ctxt tye ([], ts');
   in ts'' end;
@@ -711,8 +774,8 @@
         Syntax.string_of_term ctxt t ^ ":\n" ^
         Syntax.string_of_typ ctxt (fastype_of t));
 
-    val (Type ("fun", [T1, T2])) = fastype_of t
-      handle Bind => err_coercion ();
+    val (T1, T2) = Term.dest_funT (fastype_of t)
+      handle TYPE _ => err_coercion ();
 
     val a =
       (case T1 of
@@ -738,7 +801,7 @@
         fun complex_coercion tab G (a, b) =
           let
             val path = hd (Graph.irreducible_paths G (a, b))
-            val path' = (fst (split_last path)) ~~ tl path
+            val path' = fst (split_last path) ~~ tl path
           in Abs (Name.uu, Type (a, []),
               fold (fn t => fn u => t $ u) (map (the o Symreltab.lookup tab) path') (Bound 0))
           end;