Why do we `reduce` and `instantiateFull` constraints?
jespercockx opened this issue · comments
When playing around with instances, I noticed that Agda was reducing them even when doing so is not needed. Here is an example (with a looping function to clearly demonstrate the unwanted behavior):
open import Agda.Builtin.Nat
instance
{-# TERMINATING #-}
loop : Nat
loop = loop
get : {{Nat}} → Nat
get {{x}} = x
test : Nat
test = get
I would expect this to type-check, but instead Agda goes into a loop when type-checking the definition of test
. Looking at the debug output, the last it says is the following:
adding constraint Resolve instance argument _4 : Nat
Candidates loop : Nat
(stuck) unblocker: any()
This strongly suggests that the following call to reduce
is responsible:
agda/src/full/Agda/TypeChecking/Constraints.hs
Lines 72 to 73 in 03c15b1
The comment mentions that reduce
and instantiateFull
are necessary to reveal blocking metas, but the only blocker that is used is the one that is passed into the addConstraintTCM
, not any metas from the term (reduced or not).
The call seems to have been introduced 13 years ago by @UlfNorell for the new constraint machinery at that time:
This call will reduce and fully instantiate every constraint that we postpone, so I think it's worth investigating whether this call is actually still required.
Of course, changing such a long-standing call to instantiateFull
reveals warts where we rely implicitly on terms being fully instantiated. There are two in the Succeed
test suite:
- The test case for #4687 fails because the
dropSameCandidates
breaks. The problem here is that the non-reduced candidates have "fresh" metavariables in them that block the equality check from happening. This could presumably be fixed by callingreduce
in this function right before the fresh variable check. - The test case
LaterPrims
also breaks with a bunch of unsolved constraints, I'm not sure why but it might have something to do with theCheckLockedVars
constraint.
It also causes problems in the standard library:
Failed to solve the following constraints:
_f_185 y v = _f_185 y v : A (blocked on _f_185)
_f_185 (x • y) (x • z) = (x • y) ◦ (x • z) : A (blocked on _f_185)
(y • x) ◦ (z • x) = _f_185 (y • x) (z • x) : A (blocked on _f_185)
y ◦ z = _f_185 y z : A (blocked on _f_185)
_f_185 y z = y ◦ z : A (blocked on _f_185)
_f_164 y v = _f_164 y v : A (blocked on _f_164)
_f_164 (y • x) (z • x) = (y • x) ◦ (z • x) : A (blocked on _f_164)
(x • y) ◦ (x • z) = _f_164 (x • y) (x • z) : A (blocked on _f_164)
y ◦ z = _f_164 y z : A (blocked on _f_164)
_f_164 y z = y ◦ z : A (blocked on _f_164)
when scope checking the declaration
import Algebra.Consequences.Propositional
/home/jesper/agda/std-lib/Everything.agda:42,1-42
This requires some further investigation.
Related: #3094 (except here we are not only calling instantiateFull
but also reduce
)