-
Notifications
You must be signed in to change notification settings - Fork 373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reconstructing a (structurally smaller) aggregate from pattern-matched components trips up the totality checker #3317
Comments
The termination checker only looks for structurally smaller arguments. Working up to "matching constructors with structurally smaller arguments" would actually be a very simple change: |
Should I attempt this addition then? I'll happily prepare a PR |
You definitely should! |
I had looked into this over the last two days and the logic is working, but I ran into a snag (you have to apply the change below for the test to pass, but then perf003 fails): https://github.com/idris-lang/Idris2/compare/main...dunhamsteve:Idris2:total2?expand=1 The rule I'm using is: Constructor matches, all arguments are either equal or smaller, and at least one is smaller. So no The issue I hit is that there are some metas in a case like
But the The only difference between |
@dunhamsteve, just a guess: maybe you should try what you are doing upon #3272 |
It looks like the issue is in the normalization itself. I took out all of my changes and added one very targeted change: findCalls defs (_ ** (env, lhs, rhs_in))
= do let pargs = getArgs (delazy defs lhs)
- rhs <- normaliseOpts tcOnly defs env rhs_in
rhs <- logTime 1 "tcOnly" $ normaliseOpts ({ holesOnly := True} tcOnly) defs env rhs_in
findSC defs env Toplevel pargs (delazy defs rhs) The test looks like: 0 IdType : Type
IdType = {0 a : Type} -> a -> a
id : IdType
id = \ x : _ => x
idid : {0 a : Type} -> a -> a
idid = id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id
id id id id id id id id id id It's exponential in the number of
Aside from the test though, the totality checking works well. :) (And building |
The length of the largest implicit argument There are some real code bases where this behaviour occurs naturally so inlining all solved meta-variables for termination checking is unlikely to be feasible. Before #2977 was merged, I was traversing meta-variable solutions during termination checking and that seemed to be fast enough. Sadly, I can't find that code right now but it would be easy enough to reproduce. |
I think I've got the meta traversal working right and updated the branch. It's passing my tests and The time for a full One thing I did do for expediency is consider type constructor applications to be the |
Steps to Reproduce
I was trying this with a simple list and a NonEmpty predicate, but here's a minimal example without it:
It's possible to prove this terminates with
Control.WellFounded
, however, add some complexity going back to my original attempt:and it fails with a couple of strange error messages which I highlight below.
Expected Behavior
Idris can see that
xs
is in fact smaller than_::xs
, without much intervention from my side.Also whatever caused the strange error messages in wellfounded approach be addressed.
Observed Behavior
First (simple) attempt:
A sprinkle of
WellFounded
makes Idris happy again.Second (more complex) attempt:
S (...)
, it fails highlightingx::xs
and complaining:Error: With clause does not match parent
S $ ...
or1 ...
and a better(?) error message emerges, about both branches missing holes that need to be filled, I abbreviated the error messages, taking note to keep only the^^^
-highlighted section of the code:Circumvention:
Extra Notes:
I asked this question on an Idris community channel before filing the bug report. Initial reactions were confused.
There were suggestions that the totality checker simply makes no attempt to follow function/constructor applications. That made sense to me for functions but not for constructors (in my mind there's nothing preventing that, they're trivially reducible, and the compiler should at least easily know about
List
, in fact it has aSized
instance for it by default). However, more interestingly:in both cases we have a constructor, but in one case it's "shared" structure, while in the other it's "new".
Comparing list lengths should remove that distinction... and I'm not sure if this is the core issue here or just another observed behavior.
Moreover, the fact that
NonEmpty
is an auto-implicit changes nothing about the above, at least as far as I can tell. I tried different variants of the declaration.The text was updated successfully, but these errors were encountered: