diff --git a/src/library/unifier.cpp b/src/library/unifier.cpp index 0b252a251..6ad4548f5 100644 --- a/src/library/unifier.cpp +++ b/src/library/unifier.cpp @@ -1953,6 +1953,78 @@ struct unifier_fn { } } + /** \brief Return true iff \c rhs is of the form max(l_1 ... lhs ... l_k) , + such that l_i's do not contain lhs. + + If the result is true, then all l_i's are stored in rest. + */ + static bool generalized_check_meta(level const & m, level const & rhs, bool & found_m, buffer & rest) { + lean_assert(is_meta(m)); + if (is_max(rhs)) { + return + generalized_check_meta(m, max_lhs(rhs), found_m, rest) && + generalized_check_meta(m, max_rhs(rhs), found_m, rest); + } else if (m == rhs) { + found_m = true; + return true; + } else if (occurs_meta(m, rhs)) { + return false; + } else { + rest.push_back(rhs); + return true; + } + } + + status process_l_eq_max_core(level const & lhs, level const & rhs, justification const & jst) { + lean_assert(is_meta(lhs)); + buffer rest; + bool found_lhs = false; + if (generalized_check_meta(lhs, rhs, found_lhs, rest)) { + level r; + if (found_lhs) { + // rhs is of the form max(rest, lhs) + // Solution is lhs := max(rest, ?u) where ?u is fresh metavariable + r = mk_meta_univ(m_ngen.next()); + rest.push_back(r); + unsigned i = rest.size(); + while (i > 0) { + --i; + r = mk_max(rest[i], r); + } + r = normalize(r); + } else { + // lhs does not occur in rhs + r = rhs; + } + + if (assign(lhs, r, jst)) { + return Solved; + } else { + set_conflict(jst); + return Failed; + } + } else { + return Continue; + } + } + + /** \brief Return true iff \c is a constraint of the form + lhs =?= max(rest, lhs) + and is successfully solved. + */ + status process_l_eq_max(constraint const & c) { + lean_assert(is_level_eq_cnstr(c)); + level lhs = cnstr_lhs_level(c); + level rhs = cnstr_rhs_level(c); + justification jst = c.get_justification(); + if (is_meta(lhs)) + return process_l_eq_max_core(lhs, rhs, jst); + else if (is_meta(rhs)) + return process_l_eq_max_core(rhs, lhs, jst); + else + return Continue; + } + /** \brief Process the following constraints 1. (max l1 l2) =?= 0 OR @@ -2040,12 +2112,15 @@ struct unifier_fn { c = r.first; bool modified = r.second; if (is_level_eq_cnstr(c)) { - if (modified) + if (modified) { return process_constraint(c); + } + status st = process_l_eq_max(c); + if (st != Continue) return st == Solved; if (m_config.m_discard) { // we only try try_level_eq_zero and try_merge_max when we are discarding // constraints that canno be solved. - status st = try_level_eq_zero(c); + st = try_level_eq_zero(c); if (st != Continue) return st == Solved; if (cidx < get_group_first_index(cnstr_group::FlexFlex)) { add_cnstr(c, cnstr_group::FlexFlex); diff --git a/tests/lean/tuple.lean b/tests/lean/tuple.lean new file mode 100644 index 000000000..a6e792547 --- /dev/null +++ b/tests/lean/tuple.lean @@ -0,0 +1,9 @@ +import data.nat.basic data.prod +open nat prod + +set_option pp.universes true + +definition tuple (A : Type) (n : nat) : Type := +nat.rec_on n A (λ n r, r × A) + +check @tuple diff --git a/tests/lean/tuple.lean.expected.out b/tests/lean/tuple.lean.expected.out new file mode 100644 index 000000000..f14f0011e --- /dev/null +++ b/tests/lean/tuple.lean.expected.out @@ -0,0 +1 @@ +tuple.{l_1} : Type.{max 1 l_1} → nat → Type.{max 1 l_1}