module FStar.Tactics.PatternMatching

fsdoc: no-summary-found

fsdoc: no-comment-found

let ((mustfail #a (t:Unidentified product: [unit] (Tac a)) (message:string)):(Tac unit)):match trytac t with (Some _)  -> fail message | None  -> ()

Ensure that tactic t fails. *

let ((exact_hyp (a:Type0) (h:binder)):(Tac unit)):let  hd = quote ((FStar.Squash.return_squash #a)) in exact (mk_app hd (Prims.Cons ((FStar.Pervasives.Native.Mktuple2 (pack ((Tv_Var (bv_of_binder h)))) Q_Explicit)) (Prims.Nil )))

Use a hypothesis at type a to satisfy a goal at type squash a

let ((exact_hyp' (h:binder)):(Tac unit)):exact (pack ((Tv_Var (bv_of_binder h))))

Use a hypothesis h (of type a) to satisfy a goal at type a

let ((interp_pattern_aux (pat:pattern) (cur_bindings:bindings) (tm:term)):(Tac (match_res bindings))):admit (); let  (interp_any () cur_bindings tm) = return (Prims.Nil ) in let  (interp_var (v:varname) cur_bindings tm) = match List.Tot.assoc v cur_bindings with (Some tm')  -> if term_eq tm tm' then return cur_bindings else raise ((NonLinearMismatch ((FStar.Pervasives.Native.Mktuple3 v tm tm')))) | None  -> return ((Prims.Cons ((FStar.Pervasives.Native.Mktuple2 v tm)) cur_bindings)) in let  (interp_qn (qn:qn) cur_bindings tm) = match inspect tm with (Tv_FVar fv)  -> if =(fv_to_string fv, qn) then return cur_bindings else raise ((NameMismatch ((FStar.Pervasives.Native.Mktuple2 qn (fv_to_string fv))))) | _  -> raise ((SimpleMismatch ((FStar.Pervasives.Native.Mktuple2 pat tm)))) in let  (interp_type cur_bindings tm) = match inspect tm with (Tv_Type ())  -> return cur_bindings | _  -> raise ((SimpleMismatch ((FStar.Pervasives.Native.Mktuple2 pat tm)))) in let  (interp_app (p_hd:(p:pattern:{<<(p, pat)})) (p_arg:(p:pattern:{<<(p, pat)})) cur_bindings tm) = match inspect tm with (Tv_App hd (arg, _))  -> with_hd <- interp_pattern_aux p_hd cur_bindings hd; with_arg <- interp_pattern_aux p_arg with_hd arg; return with_arg | _  -> raise ((SimpleMismatch ((FStar.Pervasives.Native.Mktuple2 pat tm)))) in match pat with PAny  -> interp_any () cur_bindings tm | (PVar var)  -> interp_var var cur_bindings tm | (PQn qn)  -> interp_qn qn cur_bindings tm | PType  -> interp_type cur_bindings tm | (PApp p_hd p_arg)  -> interp_app p_hd p_arg cur_bindings tm | _  -> fail "?"

Match a pattern against a term. cur_bindings is a list of bindings collected while matching previous parts of the pattern. Returns a result in the exception monad. *

let ((interp_pattern (pat:pattern)):Unidentified product: [term] (Tac (match_res bindings))):(fun (tm:term) -> rev_bindings <- interp_pattern_aux pat (Prims.Nil ) tm; return (List.Tot.rev rev_bindings))

Match a pattern pat against a term. Returns a result in the exception monad. *

let ((match_term pat (tm:term)):(Tac bindings)):match interp_pattern pat (norm_term (Prims.Nil ) tm) with (Success bb)  -> bb | (Failure ex)  -> Tactics.fail (string_of_match_exception ex)

Match a term tm against a pattern pat. Raises an exception if the match fails. This is mostly useful for debugging: use mgw to capture matches. *

let ((assoc_varname_fail (#b:Type) (key:varname) (ls:list (*(varname, b)))):(Tac b)):match List.Tot.assoc key ls with None  -> fail (^("Not found: ", key)) | (Some x)  -> x

Find a varname in an association list; fail if it can't be found. *

let ((solve_mp_for_single_hyp #a (name:varname) (pat:pattern) (hypotheses:list hypothesis) (body:Unidentified product: [matching_solution] (Tac a)) (part_sol:matching_solution)):(Tac a)):match hypotheses with []  -> fail #a "No matching hypothesis" | (Prims.Cons h hs)  -> or_else ((fun () -> match interp_pattern_aux pat part_sol.ms_vars (type_of_binder h) with (Failure ex)  -> fail (^("Failed to match hyp: ", (string_of_match_exception ex))) | (Success bindings)  -> let  ms_hyps = (Prims.Cons ((FStar.Pervasives.Native.Mktuple2 name h)) part_sol.ms_hyps) in body ({part_sol with ms_vars=bindings ms_hyps=ms_hyps}))) ((fun () -> solve_mp_for_single_hyp name pat hs body part_sol))

Scan hypotheses for a match for pat that lets body succeed.

name is used to refer to the hypothesis matched in the final solution. part_sol includes bindings gathered while matching previous solutions. *

let ((solve_mp_for_hyps #a (mp_hyps:list (*(varname, pattern))) (hypotheses:list hypothesis) (body:Unidentified product: [matching_solution] (Tac a)) (partial_solution:matching_solution)):(Tac a)):match mp_hyps with []  -> body partial_solution | (Prims.Cons (name, pat) pats)  -> solve_mp_for_single_hyp name pat hypotheses (solve_mp_for_hyps pats hypotheses body) partial_solution

Scan hypotheses for matches for mp_hyps that lets body succeed. *

let ((solve_mp #a (problem:matching_problem) (hypotheses:binders) (goal:term) (body:Unidentified product: [matching_solution] (Tac a))):(Tac a)):let  goal_ps = match problem.mp_goal with None  -> {ms_vars=(Prims.Nil ) ms_hyps=(Prims.Nil )} | (Some pat)  -> match interp_pattern pat goal with (Failure ex)  -> fail (^("Failed to match goal: ", (string_of_match_exception ex))) | (Success bindings)  -> {ms_vars=bindings ms_hyps=(Prims.Nil )} in solve_mp_for_hyps #a problem.mp_hyps hypotheses body goal_ps

Solve a matching problem.

The solution returned is constructed to ensure that the continuation body succeeds: this implements the usual backtracking-match semantics. *

let ((pattern_of_term_ex tm):(Tac (match_res pattern))):match inspect tm with (Tv_Var bv)  -> return ((PVar (name_of_bv bv))) | (Tv_FVar fv)  -> let  qn = fv_to_string fv in return (if =(qn, any_qn) then PAny else (PQn qn)) | (Tv_Type ())  -> return PType | (Tv_App f (x, _))  -> let  is_any = match inspect f with (Tv_FVar fv)  -> =(fv_to_string fv, any_qn) | _  -> false in if is_any then return PAny else (fpat <- pattern_of_term_ex f; xpat <- pattern_of_term_ex x; return ((PApp fpat xpat))) | _  -> raise ((UnsupportedTermInPattern tm))

Compile a term tm into a pattern. *

let ((beta_reduce (tm:term)):(Tac term)):norm_term (Prims.Nil ) tm

β-reduce a term tm. This is useful to remove needles function applications introduced by F, like (fun a b c -> a) 1 2 3.

let ((pattern_of_term tm):(Tac pattern)):match pattern_of_term_ex tm with (Success bb)  -> bb | (Failure ex)  -> Tactics.fail (string_of_match_exception ex)

Compile a term tm into a pattern. *

let ((binders_and_body_of_abs tm):(Tac (*(binders, term)))):match inspect tm with (Tv_Abs binder tm)  -> let  (binders, body) = binders_and_body_of_abs tm in (FStar.Pervasives.Native.Mktuple2 (Prims.Cons binder binders) body) | _  -> (FStar.Pervasives.Native.Mktuple2 (Prims.Nil ) tm)

Split an abstraction tm into a list of binders and a body. *

let ((matching_problem_of_abs (tm:term)):(Tac (*(matching_problem, abspat_continuation)))):let  (binders, body) = binders_and_body_of_abs (cleanup_abspat tm) in debug (^("Got binders: ", (String.concat ", " (map ((fun b -> (name_of_binder b : (Tac string)))) binders)))); let  classified_binders = map ((fun binder -> let  bv_name = name_of_binder binder in debug (^("Got binder: ", ^(bv_name, ^("; type is ", term_to_string (type_of_binder binder))))); let  (binder_kind, typ) = classify_abspat_binder binder in ((FStar.Pervasives.Native.Mktuple4 binder bv_name binder_kind typ)))) binders in let  problem = fold_left ((fun problem (binder, bv_name, binder_kind, typ) -> debug (^("Compiling binder ", ^(name_of_binder binder, ^(", classified as ", ^(string_of_abspat_binder_kind binder_kind, ^(", with type ", term_to_string typ)))))); match binder_kind with (ABKVar _)  -> {problem with mp_vars=(Prims.Cons bv_name problem.mp_vars)} | ABKHyp  -> {problem with mp_hyps=(Prims.Cons ((FStar.Pervasives.Native.Mktuple2 bv_name (pattern_of_term typ))) problem.mp_hyps)} | ABKGoal  -> {problem with mp_goal=(Some (pattern_of_term typ))})) ({mp_vars=(Prims.Nil ) mp_hyps=(Prims.Nil ) mp_goal=None}) classified_binders in let  continuation = let  ((abspat_argspec_of_binder xx):(Tac abspat_argspec)) = match xx with (binder, xx, binder_kind, yy)  -> {asa_name=binder asa_kind=binder_kind} in ((FStar.Pervasives.Native.Mktuple2 map abspat_argspec_of_binder classified_binders tm)) in let  mp = {mp_vars=List.rev #varname problem.mp_vars mp_hyps=List.rev #(*(varname, pattern)) problem.mp_hyps mp_goal=problem.mp_goal} in debug (^("Got matching problem: ", (string_of_matching_problem mp))); (FStar.Pervasives.Native.Mktuple2 mp continuation)

Parse a notation into a matching problem and a continuation.

Pattern-matching notations are of the form (fun binders… -> continuation), where binders are of one of the forms var …, hyp …, or goal …. var binders are typed holes to be used in other binders; hyp binders indicate a pattern to be matched against hypotheses; and goal binders match the goal.

A reduction phase is run to ensure that the pattern looks reasonable; it is needed because F* tends to infer arguments in β-expanded form.

The continuation returned can't directly be applied to a pattern-matching solution; see interp_abspat_continuation below for that. *

let ((arg_type_of_binder_kind binder_kind):(Tac term)):match binder_kind with (ABKVar typ)  -> typ | ABKHyp  -> (`(binder)) | ABKGoal  -> (`(unit))

Get the (quoted) type expected by a specific kind of abspat binder. *

let (locate_fn_of_binder_kind binder_kind):match binder_kind with (ABKVar _)  -> (`(ms_locate_var)) | ABKHyp  -> (`(ms_locate_hyp)) | ABKGoal  -> (`(ms_locate_unit))

Retrieve the function used to locate a value for a given abspat binder. *

let ((abspat_arg_of_abspat_argspec solution_term (argspec:abspat_argspec)):(Tac term)):let  loc_fn = locate_fn_of_binder_kind argspec.asa_kind in let  name_tm = pack ((Tv_Const ((C_String (name_of_binder argspec.asa_name))))) in let  locate_args = (Prims.Cons ((FStar.Pervasives.Native.Mktuple2 arg_type_of_binder_kind argspec.asa_kind Q_Explicit)) (Prims.Cons ((FStar.Pervasives.Native.Mktuple2 solution_term Q_Explicit)) (Prims.Cons ((FStar.Pervasives.Native.Mktuple2 name_tm Q_Explicit)) (Prims.Nil )))) in mk_app loc_fn locate_args

Construct a term fetching the value of an abspat argument from a quoted matching solution solution_term. *

let ((specialize_abspat_continuation' (continuation:abspat_continuation) (solution_term:term)):(Tac term)):let  (mk_arg argspec) = ((FStar.Pervasives.Native.Mktuple2 abspat_arg_of_abspat_argspec solution_term argspec Q_Explicit)) in let  (argspecs, body) = continuation in mk_app body (map mk_arg argspecs)

Specialize a continuation of type abspat_continuation. This constructs a fully applied version of continuation, but it requires a quoted solution to be passed in. *

let ((specialize_abspat_continuation (continuation:abspat_continuation)):(Tac term)):let  solution_binder = fresh_binder ((`(matching_solution))) in let  solution_term = pack ((Tv_Var (bv_of_binder solution_binder))) in let  applied = specialize_abspat_continuation' continuation solution_term in let  thunked = pack ((Tv_Abs solution_binder applied)) in debug (^("Specialized into ", (term_to_string thunked))); let  normalized = beta_reduce thunked in debug (^("… which reduces to ", (term_to_string normalized))); thunked

Specialize a continuation of type abspat_continuation. This yields a quoted function taking a matching solution and running its body with appropriate bindings. *

let ((interp_abspat_continuation (a:Type0) (continuation:abspat_continuation)):(Tac (Unidentified product: [matching_solution] (Tac a)))):let  applied = specialize_abspat_continuation continuation in unquote #(Unidentified product: [matching_solution] (Tac a)) applied

Interpret a continuation of type abspat_continuation. This yields a function taking a matching solution and running the body of the continuation with appropriate bindings. *

let ((interp_abspat #a (abspat:a)):(Tac (*(matching_problem, abspat_continuation)))):matching_problem_of_abs (quote (abspat))

Construct a matching problem from an abspat. *

let ((match_abspat #b #a (abspat:a) (k:Unidentified product: [abspat_continuation] (Tac (Unidentified product: [matching_solution] (Tac b))))):(Tac b)):let  goal = cur_goal () in let  hypotheses = binders_of_env (cur_env ()) in let  (problem, continuation) = interp_abspat abspat in admit (); solve_mp #matching_solution problem hypotheses goal (k continuation)

Construct an solve a matching problem. This higher-order function isn't very usable on its own — it's mostly a convenience function to avoid duplicating the problem-parsing code. *

let ((inspect_abspat_problem #a (abspat:a)):(Tac matching_problem)):fst (interp_abspat #a abspat)

Inspect the matching problem produced by parsing an abspat. *

let ((inspect_abspat_solution #a (abspat:a)):(Tac matching_solution)):match_abspat abspat ((fun _ -> (((fun solution -> solution)) : (Tac _))))

Inspect the matching solution produced by parsing and solving an abspat. *

let ((gpm #b #a (abspat:a) ()):(Tac b)):let  (continuation, solution) = match_abspat abspat tpair in interp_abspat_continuation b continuation solution

Solve a greedy pattern-matching problem and run its continuation. This if for pattern-matching problems in the Tac effect. *

let ((pm #b #a (abspat:a)):(Tac b)):match_abspat abspat (interp_abspat_continuation b)

Solve a greedy pattern-matching problem and run its continuation. This if for pattern-matching problems in the Tac effect. *