diff --git a/src/builtin/obj/sum.olean b/src/builtin/obj/sum.olean index c8d422d1fb..d40e91c110 100644 Binary files a/src/builtin/obj/sum.olean and b/src/builtin/obj/sum.olean differ diff --git a/src/builtin/sum.lean b/src/builtin/sum.lean index 3c98b0436f..5e01be3dca 100644 --- a/src/builtin/sum.lean +++ b/src/builtin/sum.lean @@ -68,7 +68,7 @@ theorem inr_inj {A B : (Type U)} {b1 b2 : B} : inr A b1 = inr A b2 → b1 = b2 show b1 = b2, from optional::injectivity (calc some b1 = proj2 (pair (@none A) (some b1)) : refl (some b1) - ... = proj2 (pair (@none A) (some b2)) : @proj2_congr _ _ (pair (@none A) (some b1)) (pair (@none A) (some b2)) rep_eq + ... = proj2 (pair (@none A) (some b2)) : proj2_congr rep_eq ... = some b2 : refl (some b2)) theorem distinct {A B : (Type U)} (a : A) (b : B) : inl a B ≠ inr A b diff --git a/src/frontends/lean/frontend_elaborator.cpp b/src/frontends/lean/frontend_elaborator.cpp index 5ed76cb7ca..abde407405 100644 --- a/src/frontends/lean/frontend_elaborator.cpp +++ b/src/frontends/lean/frontend_elaborator.cpp @@ -41,6 +41,7 @@ struct choice_value : public value { virtual expr get_type() const { lean_unreachable(); } // LCOV_EXCL_LINE virtual void write(serializer & ) const { lean_unreachable(); } // LCOV_EXCL_LINE virtual name get_name() const { return name("Choice"); } + virtual bool is_atomic_pp(bool /* unicode */, bool /* coercion */) const { return false; } // NOLINT virtual void display(std::ostream & out) const { out << "(Choice"; for (auto c : m_choices) { diff --git a/src/frontends/lean/pp.cpp b/src/frontends/lean/pp.cpp index 3ee879ba56..c29d1b2cc2 100644 --- a/src/frontends/lean/pp.cpp +++ b/src/frontends/lean/pp.cpp @@ -262,7 +262,7 @@ class pp_fn { case expr_kind::Var: case expr_kind::Constant: case expr_kind::Type: return true; case expr_kind::Value: - return !is_choice(e); + return to_value(e).is_atomic_pp(m_unicode, m_coercion); case expr_kind::MetaVar: return !metavar_lctx(e); case expr_kind::App: diff --git a/src/kernel/expr.h b/src/kernel/expr.h index fc1350661c..c229af2043 100644 --- a/src/kernel/expr.h +++ b/src/kernel/expr.h @@ -331,6 +331,7 @@ public: virtual void display(std::ostream & out) const; virtual format pp() const; virtual format pp(bool unicode, bool coercion) const; + virtual bool is_atomic_pp(bool unicode, bool coercion) const = 0; virtual int push_lua(lua_State * L) const; virtual unsigned hash() const; virtual void write(serializer & s) const = 0; diff --git a/src/kernel/normalizer.cpp b/src/kernel/normalizer.cpp index d556d0e2a9..20f42d7659 100644 --- a/src/kernel/normalizer.cpp +++ b/src/kernel/normalizer.cpp @@ -67,6 +67,7 @@ public: expr const & get_expr() const { return m_expr; } context const & get_context() const { return m_ctx; } value_stack const & get_stack() const { return m_stack; } + virtual bool is_atomic_pp(bool /* unicode */, bool /* coercion */) const { return false; } // NOLINT }; expr mk_closure(expr const & e, context const & ctx, value_stack const & s) { return mk_value(*(new closure(e, ctx, s))); } diff --git a/src/kernel/value.h b/src/kernel/value.h index 0ad7336a1f..bb0e43b484 100644 --- a/src/kernel/value.h +++ b/src/kernel/value.h @@ -17,6 +17,7 @@ public: named_value(name const & n):m_name(n) {} virtual ~named_value() {} virtual name get_name() const { return m_name; } + virtual bool is_atomic_pp(bool /* unicode */, bool /* coercion */) const { return true; } // NOLINT }; /** diff --git a/src/library/arith/int.cpp b/src/library/arith/int.cpp index 9393700590..2f3f98b466 100644 --- a/src/library/arith/int.cpp +++ b/src/library/arith/int.cpp @@ -44,6 +44,7 @@ public: else return format(m_val); } + virtual bool is_atomic_pp(bool /* unicode */, bool coercion) const { return !coercion || m_val < 0; } virtual unsigned hash() const { return m_val.hash(); } virtual int push_lua(lua_State * L) const { return push_mpz(L, m_val); } mpz const & get_num() const { return m_val; } diff --git a/src/library/arith/nat.cpp b/src/library/arith/nat.cpp index 37f611e691..ec575c4181 100644 --- a/src/library/arith/nat.cpp +++ b/src/library/arith/nat.cpp @@ -36,6 +36,7 @@ public: virtual void display(std::ostream & out) const { out << m_val; } virtual format pp() const { return format(m_val); } virtual format pp(bool, bool) const { return pp(); } + virtual bool is_atomic_pp(bool /* unicode */, bool /* coercion */) const { return true; } // NOLINT virtual unsigned hash() const { return m_val.hash(); } virtual int push_lua(lua_State * L) const { return push_mpz(L, m_val); } mpz const & get_num() const { return m_val; } diff --git a/src/library/arith/real.cpp b/src/library/arith/real.cpp index ed8a8a5fbf..0ff87f0e2d 100644 --- a/src/library/arith/real.cpp +++ b/src/library/arith/real.cpp @@ -48,6 +48,7 @@ public: else return format(m_val); } + virtual bool is_atomic_pp(bool /* unicode */, bool coercion) const { return !coercion; } virtual unsigned hash() const { return m_val.hash(); } virtual int push_lua(lua_State * L) const { return push_mpq(L, m_val); } mpq const & get_num() const { return m_val; } diff --git a/src/library/elaborator/elaborator.cpp b/src/library/elaborator/elaborator.cpp index 032a4e36bf..dc3a75633b 100644 --- a/src/library/elaborator/elaborator.cpp +++ b/src/library/elaborator/elaborator.cpp @@ -538,11 +538,6 @@ class elaborator::imp { swap(new_a, new_b); push_new_constraint(is_eq(c), *new_ctx, new_a, new_b, new_jst); return Processed; - } else if (!has_metavar(b)) { - // Failure, there is no way to unify - // ?m[lift:s:n, ...] with a term that contains variables in [s, s+n] - m_conflict = mk_failure_justification(c); - return Failed; } } } @@ -562,6 +557,28 @@ class elaborator::imp { return Continue; } + bool check_metavar_lift(unification_constraint const & c, expr const & a, expr const & b) { + if (is_metavar(a) && has_local_context(a) && !has_metavar(b)) { + lean_assert(!is_assigned(a)); + local_entry const & me = head(metavar_lctx(a)); + if (me.is_lift()) { + // a is of the form ?m[lift:s:n] + unsigned s = me.s(); + unsigned n = me.n(); + if (has_free_var(b, s, s + n, m_state.m_menv)) { + // Failure, there is no way to unify + // ?m[lift:s:n, ...] with a term that contains variables in [s, s+n] + + // In older commits, this check was being done inside of process_metavar. + // This was incorrect. This check must be performed AFTER b is normalized. + m_conflict = mk_failure_justification(c); + return false; + } + } + } + return true; + } + justification mk_subst_justification(unification_constraint const & c, buffer const & subst_justifications) { if (subst_justifications.size() == 1) { return justification(new substitution_justification(c, subst_justifications[0])); @@ -729,6 +746,8 @@ class elaborator::imp { expr new_a = normalize_step(ctx, a); expr new_b = normalize_step(ctx, b); if (new_a == a && new_b == b) { + if (is_meta(a) || is_meta(b)) + break; // we do not unfold if one of the arguments is a metavar or metavar_app int w_a = get_unfolding_weight(a); int w_b = get_unfolding_weight(b); if (w_a >= 0 || w_b >= 0) { @@ -1687,7 +1706,9 @@ class elaborator::imp { } } - if (!is_meta(a) && !is_meta(b) && normalize_head(a, b, c)) { return true; } + if (!is_meta_app(a) && !is_meta_app(b) && normalize_head(a, b, c)) { return true; } + + if (!check_metavar_lift(c, a, b) || !check_metavar_lift(c, b, a)) { return false; } if (process_simple_ho_match(ctx, a, b, true, c) || process_simple_ho_match(ctx, b, a, false, c))