+let discriminate'_tac ~term =
+ let module C = Cic in
+ let module U = UriManager in
+ let module P = PrimitiveTactics in
+ let module T = Tacticals in
+ let fail msg = raise (ProofEngineTypes.Fail (lazy ("Discriminate: " ^ msg))) in
+ let find_discriminating_consno t1 t2 =
+ let rec aux t1 t2 =
+ match t1, t2 with
+ | C.MutConstruct _, C.MutConstruct _ when t1 = t2 -> None
+ | C.Appl ((C.MutConstruct _ as constr1) :: args1),
+ C.Appl ((C.MutConstruct _ as constr2) :: args2)
+ when constr1 = constr2 ->
+ let rec aux_list l1 l2 =
+ match l1, l2 with
+ | [], [] -> None
+ | hd1 :: tl1, hd2 :: tl2 ->
+ (match aux hd1 hd2 with
+ | None -> aux_list tl1 tl2
+ | Some _ as res -> res)
+ | _ -> (* same constructor applied to a different number of args *)
+ assert false
+ in
+ aux_list args1 args2
+ | ((C.MutConstruct (_,_,consno1,subst1)),
+ (C.MutConstruct (_,_,consno2,subst2)))
+ | ((C.MutConstruct (_,_,consno1,subst1)),
+ (C.Appl ((C.MutConstruct (_,_,consno2,subst2)) :: _)))
+ | ((C.Appl ((C.MutConstruct (_,_,consno1,subst1)) :: _)),
+ (C.MutConstruct (_,_,consno2,subst2)))
+ | ((C.Appl ((C.MutConstruct (_,_,consno1,subst1)) :: _)),
+ (C.Appl ((C.MutConstruct (_,_,consno2,subst2)) :: _)))
+ when (consno1 <> consno2) || (subst1 <> subst2) ->
+ Some consno2
+ | _ -> fail "not a discriminable equality"
+ in
+ aux t1 t2
+ in
+ let mk_pattern turi typeno consno context left_args =
+ (* a list of "True" except for the element in position consno which
+ * is "False" *)
+ match fst (CicEnvironment.get_obj CicUniv.empty_ugraph turi) with
+ | C.InductiveDefinition (ind_type_list,_,nr_ind_params,_) ->
+ let _,_,_,constructor_list = List.nth ind_type_list typeno in
+ let false_constr_id,_ = List.nth constructor_list (consno - 1) in
+ List.map
+ (fun (id,cty) ->
+ (* dubbio: e' corretto ridurre in questo context ??? *)
+ let red_ty = CicReduction.whd context cty in
+ let rec aux t k =
+ match t with
+ | C.Prod (_,_,target) when (k <= nr_ind_params) ->
+ CicSubstitution.subst (List.nth left_args (k-1))
+ (aux target (k+1))
+ | C.Prod (binder,source,target) when (k > nr_ind_params) ->
+ C.Lambda (binder, source, (aux target (k+1)))
+ | _ ->
+ if (id = false_constr_id)
+ then (C.MutInd(LibraryObjects.false_URI (),0,[]))
+ else (C.MutInd(LibraryObjects.true_URI (),0,[]))
+ in
+ (CicSubstitution.lift 1 (aux red_ty 1)))
+ constructor_list
+ | _ -> (* object is not an inductive definition *)
+ assert false
+ in
+ let discriminate'_tac ~term status =
+ let (proof, goal) = status in
+ let _,metasenv,_,_ = proof in
+ let _,context,_ = CicUtil.lookup_meta goal metasenv in
+ let termty,_ =
+ CicTypeChecker.type_of_aux' metasenv context term CicUniv.empty_ugraph
+ in
+ match termty with
+ | (C.Appl [(C.MutInd (equri, 0, [])) ; tty ; t1 ; t2])
+ when LibraryObjects.is_eq_URI equri ->
+ let turi,typeno,exp_named_subst,left_args =
+ match tty with
+ | (C.MutInd (turi,typeno,exp_named_subst)) ->
+ turi,typeno,exp_named_subst,[]
+ | (C.Appl (C.MutInd (turi,typeno,exp_named_subst)::left_args)) ->
+ turi,typeno,exp_named_subst,left_args
+ | _ -> fail "not a discriminable equality"
+ in
+ let consno =
+ match find_discriminating_consno t1 t2 with
+ | Some consno -> consno
+ | None -> fail "discriminating terms are structurally equal"
+ in
+ let pattern = mk_pattern turi typeno consno context left_args in
+ let (proof',goals') =
+ ProofEngineTypes.apply_tactic
+ (EliminationTactics.elim_type_tac
+ (C.MutInd (LibraryObjects.false_URI (), 0, [])))
+ status
+ in
+ (match goals' with
+ | [goal'] ->
+ let _,metasenv',_,_ = proof' in
+ let _,context',gty' = CicUtil.lookup_meta goal' metasenv' in
+ ProofEngineTypes.apply_tactic
+ (T.then_
+ ~start:
+ (ReductionTactics.change_tac
+ ~pattern:(ProofEngineTypes.conclusion_pattern (Some gty'))
+ (fun _ m u ->
+ C.Appl [
+ C.Lambda ( C.Name "x", tty,
+ C.MutCase (turi, typeno,
+ (C.Lambda ((C.Name "x"),
+ (CicSubstitution.lift 1 tty),
+ (C.Sort C.Prop))),
+ (C.Rel 1), pattern));
+ t2 ], m, u))
+ ~continuation:
+ (T.then_
+ ~start:
+ (EqualityTactics.rewrite_simpl_tac
+ ~direction:`RightToLeft
+ ~pattern:(ProofEngineTypes.conclusion_pattern None)
+ term)
+ ~continuation:
+ (IntroductionTactics.constructor_tac ~n:1)))
+ (proof',goal')
+ | [] -> fail "ElimType False left no goals"
+ | _ -> fail "ElimType False left more than one goal")
+ | _ -> fail "not an equality"
+ in
+ ProofEngineTypes.mk_tactic (discriminate'_tac ~term)
+
+let discriminate_tac ~term =
+ let discriminate_tac ~term status =
+ ProofEngineTypes.apply_tactic
+ (Tacticals.then_
+ ~start:(* (injection_tac ~term) *) Tacticals.id_tac
+ ~continuation:(discriminate'_tac ~term)) (* NOOO!!! non term ma una (qualunque) delle nuove hyp introdotte da inject *)
+ status
+ in
+ ProofEngineTypes.mk_tactic (discriminate_tac ~term)