feat(frontends/lean,library/tactic/tactic_state): improve error localization
This commit is contained in:
parent
bbf21b4e65
commit
3c71d7eda2
6 changed files with 53 additions and 19 deletions
|
|
@ -24,7 +24,7 @@ meta instance : has_to_format tactic_state :=
|
|||
|
||||
inductive tactic_result (A : Type)
|
||||
| success : A → tactic_state → tactic_result
|
||||
| exception : (unit → format) → tactic_state → tactic_result
|
||||
| exception : (unit → format) → option expr → tactic_state → tactic_result
|
||||
|
||||
open tactic_result
|
||||
|
||||
|
|
@ -33,8 +33,8 @@ variables {A : Type}
|
|||
variables [has_to_string A]
|
||||
|
||||
meta definition tactic_result_to_string : tactic_result A → string
|
||||
| (success a s) := to_string a
|
||||
| (exception .A e s) := "Exception: " ++ to_string (e ())
|
||||
| (success a s) := to_string a
|
||||
| (exception .A t ref s) := "Exception: " ++ to_string (t ())
|
||||
|
||||
meta instance : has_to_string (tactic_result A) :=
|
||||
⟨tactic_result_to_string⟩
|
||||
|
|
@ -66,7 +66,7 @@ meta definition tactic_return (a : A) : tactic A :=
|
|||
meta definition tactic_orelse {A : Type} (t₁ t₂ : tactic A) : tactic A :=
|
||||
λ s, tactic_result.cases_on (t₁ s)
|
||||
success
|
||||
(λ e₁ s', tactic_result.cases_on (t₂ s)
|
||||
(λ e₁ ref₁ s', tactic_result.cases_on (t₂ s)
|
||||
success
|
||||
(exception A))
|
||||
end
|
||||
|
|
@ -75,7 +75,7 @@ meta instance : monad tactic :=
|
|||
⟨@tactic_fmap, @tactic_return, @tactic_bind⟩
|
||||
|
||||
meta definition tactic.fail {A B : Type} [has_to_format B] (msg : B) : tactic A :=
|
||||
λ s, exception A (λ u, to_fmt msg) s
|
||||
λ s, exception A (λ u, to_fmt msg) none s
|
||||
|
||||
meta definition tactic.failed {A : Type} : tactic A :=
|
||||
tactic.fail "failed"
|
||||
|
|
@ -89,7 +89,7 @@ variables {A : Type}
|
|||
meta definition try (t : tactic A) : tactic unit :=
|
||||
λ s, tactic_result.cases_on (t s)
|
||||
(λ a, success ())
|
||||
(λ e s', success () s)
|
||||
(λ e ref s', success () s)
|
||||
|
||||
meta definition skip : tactic unit :=
|
||||
success ()
|
||||
|
|
@ -116,13 +116,13 @@ repeat_at_most 100000
|
|||
meta definition returnex (e : exceptional A) : tactic A :=
|
||||
λ s, match e with
|
||||
| (exceptional.success a) := tactic_result.success a s
|
||||
| (exceptional.exception .A f) := tactic_result.exception A (λ u, f options.mk) s -- TODO(Leo): extract options from environment
|
||||
| (exceptional.exception .A f) := tactic_result.exception A (λ u, f options.mk) none s -- TODO(Leo): extract options from environment
|
||||
end
|
||||
|
||||
meta definition returnopt (e : option A) : tactic A :=
|
||||
λ s, match e with
|
||||
| (some a) := tactic_result.success a s
|
||||
| none := tactic_result.exception A (λ u, to_fmt "failed") s
|
||||
| none := tactic_result.exception A (λ u, to_fmt "failed") none s
|
||||
end
|
||||
|
||||
/- Decorate t's exceptions with msg -/
|
||||
|
|
|
|||
|
|
@ -2133,8 +2133,15 @@ void elaborator::invoke_tactic(expr const & mvar, expr const & tactic) {
|
|||
m_env = new_s->env();
|
||||
m_ctx.set_env(m_env);
|
||||
m_ctx.set_mctx(mctx);
|
||||
} else if (optional<pair<format, tactic_state>> ex = is_tactic_exception(S, m_opts, r)) {
|
||||
throw_unsolved_tactic_state(ex->second, ex->first, ref);
|
||||
} else if (optional<tactic_exception_info> ex = is_tactic_exception(S, r)) {
|
||||
format fmt = std::get<0>(*ex);
|
||||
optional<expr> ref1 = std::get<1>(*ex);
|
||||
tactic_state s1 = std::get<2>(*ex);
|
||||
pos_info_provider * provider = get_pos_info_provider();
|
||||
if (ref1 && provider && provider->get_pos_info(*ref1))
|
||||
throw elaborator_exception(*ref1, fmt);
|
||||
else
|
||||
throw_unsolved_tactic_state(s1, fmt, ref);
|
||||
} else {
|
||||
lean_unreachable();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,12 +223,15 @@ optional<tactic_state> is_tactic_success(vm_obj const & o) {
|
|||
}
|
||||
}
|
||||
|
||||
optional<pair<format, tactic_state>> is_tactic_exception(vm_state & S, options const & opts, vm_obj const & ex) {
|
||||
optional<tactic_exception_info> is_tactic_exception(vm_state & S, vm_obj const & ex) {
|
||||
if (is_constructor(ex) && cidx(ex) == 1) {
|
||||
vm_obj fmt = S.invoke(cfield(ex, 0), to_obj(opts));
|
||||
return optional<pair<format, tactic_state>>(mk_pair(to_format(fmt), to_tactic_state(cfield(ex, 1))));
|
||||
vm_obj fmt = S.invoke(cfield(ex, 0), mk_vm_unit());
|
||||
optional<expr> ref;
|
||||
if (!is_none(cfield(ex, 1)))
|
||||
ref = to_expr(get_some_value(cfield(ex, 1)));
|
||||
return optional<tactic_exception_info>(to_format(fmt), ref, to_tactic_state(cfield(ex, 2)));
|
||||
} else {
|
||||
return optional<pair<format, tactic_state>>();
|
||||
return optional<tactic_exception_info>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,13 +244,23 @@ vm_obj mk_tactic_success(tactic_state const & s) {
|
|||
}
|
||||
|
||||
vm_obj mk_tactic_exception(vm_obj const & fn, tactic_state const & s) {
|
||||
return mk_vm_constructor(1, fn, to_obj(s));
|
||||
return mk_vm_constructor(1, fn, mk_vm_none(), to_obj(s));
|
||||
}
|
||||
|
||||
vm_obj mk_tactic_exception(vm_obj const & fn, vm_obj const & ref, tactic_state const & s) {
|
||||
return mk_vm_constructor(1, fn, ref, to_obj(s));
|
||||
}
|
||||
|
||||
vm_obj mk_tactic_exception(throwable const & ex, tactic_state const & s) {
|
||||
vm_obj _ex = to_obj(ex);
|
||||
vm_obj fn = mk_vm_closure(get_throwable_to_format_fun_idx(), 1, &_ex);
|
||||
return mk_tactic_exception(fn, s);
|
||||
optional<expr> ref;
|
||||
if (auto kex = dynamic_cast<ext_exception const *>(&ex))
|
||||
ref = kex->get_main_expr();
|
||||
else if (auto fex = dynamic_cast<formatted_exception const *>(&ex))
|
||||
ref = fex->get_main_expr();
|
||||
vm_obj _ref = ref ? mk_vm_some(to_obj(*ref)) : mk_vm_none();
|
||||
return mk_tactic_exception(fn, _ref, s);
|
||||
}
|
||||
|
||||
vm_obj mk_tactic_exception(format const & fmt, tactic_state const & s) {
|
||||
|
|
|
|||
|
|
@ -108,9 +108,11 @@ format pp_indented_expr(tactic_state const & s, expr const & e);
|
|||
/* If r is (base_tactic_result.success a s), then return s */
|
||||
optional<tactic_state> is_tactic_success(vm_obj const & r);
|
||||
|
||||
/* If ex is (base_tactic_result.exception fn), then return (fn opts).
|
||||
The vm_state S is used to execute (fn opts). */
|
||||
optional<pair<format, tactic_state>> is_tactic_exception(vm_state & S, options const & opts, vm_obj const & ex);
|
||||
typedef std::tuple<format, optional<expr>, tactic_state> tactic_exception_info;
|
||||
|
||||
/* If ex is (base_tactic_result.exception fn), then return (fn ()).
|
||||
The vm_state S is used to execute (fn ()). */
|
||||
optional<tactic_exception_info> is_tactic_exception(vm_state & S, vm_obj const & ex);
|
||||
|
||||
type_context mk_type_context_for(tactic_state const & s, transparency_mode m = transparency_mode::Semireducible);
|
||||
type_context mk_type_context_for(tactic_state const & s, local_context const & lctx, transparency_mode m = transparency_mode::Semireducible);
|
||||
|
|
|
|||
6
tests/lean/auto_quote_error.lean
Normal file
6
tests/lean/auto_quote_error.lean
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
example (a b c : nat) : a = b → b = c → c = a :=
|
||||
begin
|
||||
intro h1,
|
||||
intro h2,
|
||||
exact eq.symm (eq.trans h1 _),
|
||||
end
|
||||
6
tests/lean/auto_quote_error.lean.expected.out
Normal file
6
tests/lean/auto_quote_error.lean.expected.out
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
auto_quote_error.lean:5:29: error: don't know how to synthesize placeholder
|
||||
state:
|
||||
a b c : ℕ,
|
||||
h1 : a = b,
|
||||
h2 : b = c
|
||||
⊢ b = c
|
||||
Loading…
Add table
Reference in a new issue