@joehendrix This commit is implementing the matcher that postpones
implicit arguments. The lemma get_data_mk_byte can be proved without
using any hacks in the type_context unifier.
I also added the trace class: simplify.implicit_failure
If we use the command
set_option trace.simplify.implicit_failure true
Then, the simplifier will generate a diagnostic message every time it
succeeds in the explicit part, but fails in the implicit one.
Please feel free to suggest a better name to his option.
BTW, we can now easily extend the matcher with additional features.
I'm wondering if we will eventually want to write some of these
extensions in Lean.
Fixes#1363
After error recovery has been implemented in the elaborator, a few
assumptions made in the type context are not valid anymore since we may
be recovering from errors, and the local and metavariable contexts may
be invalid.
I used the approach used in the class environment.
- find* methods return optional<...>
- get* methods throw exception for unknown elements
Remarks:
I preserved code patterns such as
optional<local_decl> d = lctx.find_local_decl(...)
lean_assert(d)
and did not convert them into
local_decl d = lctx.get_local_decl(...)
Reason: the intention is clear that the local must be defined there.
If it is not we should analyze the problem and decide whether we should
throw an exception or not.
However, I converted code patterns such as
local_decl d = *lctx.find_local_decl(...)
into
local_decl d = lctx.get_local_decl(...)
Disclaimer: this change fixes issue #1363, but it may obfuscate other bugs.
It was being stored in the environment before. This was very hackish,
and it was producing a series of unnecessary environment updates, and
thread local caches invalidations.
The new test tests/lean/run/heap.lean is 5x-6x faster after this commit.
They were at src/library because we hoped we would be able to use them
in the type_context unifier. However, the plan did not work for several
reasons. We saved the partial implementation in the branch: https://github.com/leodemoura/lean/tree/type_context_with_refl_lemmas
Here are the problems:
1) We have to be able to rewrite even when the type context is already in tmp-mode.
This is an issue because the tmp metavariables in the refl lemma clash with the ones created in the type context.
Solution: implemented lift operation for idx metavariables, and custom
match. This solution is not perfect since the lifting is extra overhead.
2) The term being "unfolded" may be stuck. Example:
nat.add n (@one nat ?m)
will not match the pattern
nat.add ?x_0 (nat.succ ?x_1)
because ?m is not assigned yet.
We can assign it during the matching process because it is a regular metavariable and the matching is performed in
tmp_mode.
Possible workaround a) try to instanciate type class instances before we try the refl lemmas.
This is a potential performance problem because the term can be arbitrarily big.
The current heuristics we use to speed up the process do not work for the example above.
Possible workaround b) allow regular metavariables be assigned by type class resolution even
when we are in tmp-mode.
We have not tried to implement any of these workarounds.
3) There are many more lazy-delta steps. Before this feature, when we unfold `nat.add a (succ ... (succ b) ...)`,
we are done with delta-reduction. It is just iota and beta after that.
However, with refl-lemmas, the term `nat.add a (succ ... (succ b) ...)` produces one lazy-delta step per succ.
This produces nasty side-effects because of the
The heuristic (f t =?= f s) ==> (t =?= s).
Examples such as
(fib 8) =?= 34
will take a very long time because of this heuristic.
Possible workaround: cache failures like we did in Lean2.
However, failure are only easy to cache if there are no meta-variables.
4) The type context trace gets very confusing since we use is_def_eq for matching lhs while we are computing is_def_eq.
Possible workaround: disable trace when trying refl_lemmas.
5) We must be able to temporarily disable the feature.
Example: when proving a refl_lemma for a definition `f`, we may have
to expand the nested definitions
(e.g., for match-end blocks)
6) refl/simp lemmas were designed to rewrite elaborated terms.
Using them during unification may produce a series of unexpected
behaviors since terms usually contain many regular and universe meta-variables.
7) We need to define a notion of "refl stuck application".
Right now, a metavar is stuck, a projection is stuck if the structure
is stuck, a recursor is stuck is the major premise is stuck.
An application (f ...) is refl-lemma stuck if f has refl-lemmas
associated with it, AND metavariables occurring in arguments are
preventing a refl-lemma from being applied.
Before this commit, we were inferring whether an
inductive/structure/class were meta or not. This was bad since the user
had no clue whether the type was trusted (non meta) or not.
Moreover, users could get confused by this behavior and assume the
kernel was allowing trusted code to rely on untrusted one.