It produces non-termination because it triggers sub-problems of the
form (has_monad_lift_t t ?M), and this kind of sub-problem is bad
for the transitive closure rule:
instance has_monad_lift_t_trans (m n o) [has_monad_lift n o] [has_monad_lift_t m n] : has_monad_lift_t m o
The trick above only behaves well for synthesis subproblems that do not
contain sub-variables.
Note that the sub-problem (has_monad_lift_t t ?M) is created by a
similar rule used at has_coe_t.
instance {a : Type u₁} {b : Type u₂} {c : Type u₃} [has_coe a b] [has_coe_t b c] : has_coe_t a c
AND
instance {m n} [has_monad_lift_t m n] {α} : has_coe (m α) (n α) :=
We workaround the issue by disabling
instance {m n} [has_monad_lift_t m n] {α} : has_coe (m α) (n α)
and adding instances of it. Example:
meta instance (α : Type) : has_coe (tactic α) (solver α) := ...
meta instance (α : Type) : has_coe (tactic α) (prover α) := ...
meta instance (α : Type) : has_coe (tactic α) (smt_tactic α) := ...
We also removed the notation (♯tac) since it is not needed anymore.
@gebner, the comment at elaborator.cpp explains why you had to use the ♯
notation. The workaround is a little bit hackish, but I think it is
worth it. We will use monad lifts in many different places.