| ((C.Appl ((C.MutConstruct (uri1,typeno1,consno1,exp_named_subst1))::applist1)),
                        (C.Appl ((C.MutConstruct (uri2,typeno2,consno2,exp_named_subst2))::applist2)))
                          when (uri1 = uri2) && (typeno1 = typeno2) && (consno1 = consno2) && (exp_named_subst1 = exp_named_subst2) ->
-                       let rec traverse_list i l1 l2 =
+                       let rec traverse_list i liftno l1 l2 =
                          match l1,l2 with
                             [],[] -> T.id_tac
                           | hd1::tl1,hd2::tl2 -> 
-                             T.then_ 
-                              ~start:
-                                (injection1_tac ~i
-                                  ~term:(CicSubstitution.lift (i-1) term))
-                              ~continuation:(traverse_list (i+1) tl1 tl2)
+                             if
+                              fst
+                               (CicReduction.are_convertible ~metasenv
+                                 context hd1 hd2 CicUniv.empty_ugraph)
+                             then
+                              traverse_list (i+1) liftno tl1 tl2
+                             else
+                              T.then_ 
+                               ~start:
+                                 (injection1_tac ~i ~liftno
+                                   ~term:(CicSubstitution.lift liftno term))
+                               ~continuation:
+                                 (traverse_list (i+1) (liftno+1) tl1 tl2)
                           | _ -> raise (ProofEngineTypes.Fail (lazy "Discriminate: i 2 termini hanno in testa lo stesso costruttore, ma applicato a un numero diverso di termini. possibile???"))
-                       in traverse_list 1 applist1 applist2
+                       in traverse_list 1 0 applist1 applist2
                     | ((C.MutConstruct (uri1,typeno1,consno1,exp_named_subst1)),
                        (C.MutConstruct (uri2,typeno2,consno2,exp_named_subst2)))
                     | ((C.MutConstruct (uri1,typeno1,consno1,exp_named_subst1)),
  in 
   ProofEngineTypes.mk_tactic (injection_tac ~term)
 
-and injection1_tac ~term ~i = 
+and injection1_tac ~term ~i ~liftno = 
  let injection1_tac ~term ~i status =
   let (proof, goal) = status in
   (* precondizione: t1 e t2 hanno in testa lo stesso costruttore ma differiscono (o potrebbero differire?) nell'i-esimo parametro del costruttore *)
                             | _ ->
                                let nr_param_constr = k - 1 - paramsno in
                                 if id = i_constr_id
-                                 then C.Rel (nr_param_constr - i + 1)
+                                 then C.Rel (nr_param_constr - liftno)
                                  else S.lift (nr_param_constr + 1) t1' (* + 1 per liftare anche il lambda aggiunto esternamente al case *)
                           in aux reduced_cty 1
                        ) constructor_list in
                        (fun status ->    
                          let (proof, goal) = status in
                          let _,metasenv,_,_ = proof in
-                          let _,context,gty = CicUtil.lookup_meta goal metasenv in
+                          let _,context,gty =
+                           CicUtil.lookup_meta goal metasenv
+                          in
                            let new_t1' = 
                             match gty with 
                                (C.Appl (C.MutInd (_,_,_)::arglist)) -> 
                                 List.nth arglist 1
-                             | _ -> raise (ProofEngineTypes.Fail (lazy "Injection: goal after cut is not correct"))
+                             | _ ->
+                               raise
+                                (ProofEngineTypes.Fail
+                                  (lazy
+                                    "Injection: goal after cut is not correct"))
                            in
+let aaa =
                             ProofEngineTypes.apply_tactic 
                             (ReductionTactics.change_tac
                                ~pattern:(ProofEngineTypes.conclusion_pattern
                                       (turi,typeno,outtype,C.Rel 1,patterns)) ;
                                   t1]
 in
-(*prerr_endline ("XXX: " ^ CicPp.ppterm xxx);*)
+prerr_endline ("XXX: " ^ CicPp.ppterm xxx);
+prerr_endline ("WITH: " ^ CicPp.ppterm new_t1');
 xxx,
                                  m, u))
                         status
+in
+prerr_endline "OK";
+aaa
                        ))
                      ~continuation:
                        (T.then_
                        )
                    ])     
                   status
-            | _ -> raise (ProofEngineTypes.Fail (lazy "Discriminate: not a discriminable equality"))
+            | _ -> raise (ProofEngineTypes.Fail (lazy "Injection: not an equality over elements of an inductive type"))
            )
-        | _ -> raise (ProofEngineTypes.Fail (lazy "Discriminate: not an equality"))
+        | _ -> ProofEngineTypes.apply_tactic T.id_tac status (*XXXraise (ProofEngineTypes.Fail (lazy "Injection: not an equality"))*)
  in
   ProofEngineTypes.mk_tactic (injection1_tac ~term ~i)
 ;;
 
--- /dev/null
+(**************************************************************************)
+(*       ___                                                              *)
+(*      ||M||                                                             *)
+(*      ||A||       A project by Andrea Asperti                           *)
+(*      ||T||                                                             *)
+(*      ||I||       Developers:                                           *)
+(*      ||T||         The HELM team.                                      *)
+(*      ||A||         http://helm.cs.unibo.it                             *)
+(*      \   /                                                             *)
+(*       \ /        This file is distributed under the terms of the       *)
+(*        v         GNU General Public License Version 2                  *)
+(*                                                                        *)
+(**************************************************************************)
+
+set "baseuri" "cic:/matita/test/injection/".
+
+include "legacy/coq.ma".
+
+alias id "nat" = "cic:/Coq/Init/Datatypes/nat.ind#xpointer(1/1)".
+alias id "bool" = "cic:/Coq/Init/Datatypes/bool.ind#xpointer(1/1)".
+alias id "S" = "cic:/Coq/Init/Datatypes/nat.ind#xpointer(1/1/2)".
+
+inductive t0 : Type :=
+   k0 : nat → nat → t0
+ | k0' : bool → bool → t0.
+
+theorem injection_test0: ∀n,n',m,m'. k0 n m = k0 n' m' → m = m'.
+ intros;
+ injection H;
+ assumption.
+qed.
+
+inductive t : Type → Type :=
+   k : nat → t nat
+ | k': bool → t bool.
+ 
+theorem injection_test1: ∀n,n'. k n = k n' → n = n'.
+ intros;
+ injection H;
+ assumption.
+qed.
+
+inductive tt (A:Type) : Type -> Type :=
+   k1: nat → nat → tt A nat
+ | k2: bool → bool → tt A bool.
+ 
+theorem injection_test2: ∀n,n',m,m'. k1 bool n n' = k1 bool m m' → n' = m'.
+ intros;
+ injection H;
+ assumption.
+qed.
+
+inductive ttree : Type → Type :=
+   tempty: ttree nat
+ | tnode : ∀A. ttree A → ttree A → ttree A.
+
+theorem injection_test3:
+ ∀t,t'. tnode nat t tempty = tnode nat t' tempty → t = t'.
+ intros;
+ injection H;
+ assumption.
+qed.
+
+theorem injection_test3:
+ ∀t,t'.
+  tnode nat (tnode nat t t') tempty = tnode nat (tnode nat t' tempty) tempty →
+   t = t'.
+ intros;
+ injection H;
+ 
+
+theorem injection_test4:
+ ∀n,n',m,m'. k1 bool (S n) (S m) = k1 bool (S n') (S (S m')) → m = S m'.
+ intros;
+ injection H;
+ assumption.
+qed.
+
+