fix: Use whnf for mutual recursion with types hiding (#2926)

the code stumbled over recursive functions whose type doesn’t have
enough manifest foralls, like:

```
def FunType := Nat → Nat

mutual
def foo : FunType
  | .zero => 0
  | .succ n => bar n
def bar : FunType
  | .zero => 0
  | .succ n => foo n
end
termination_by foo n => n; bar n => n
```

This can be fixed by using `whnf` in appropriate places, to expose the
`.forall` constructor.

Fixes #2925, comes with test case.
This commit is contained in:
Joachim Breitner 2023-11-22 12:31:36 +01:00 committed by GitHub
parent 9efdde23e0
commit 54dd588fc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 5 deletions

View file

@ -124,7 +124,8 @@ where
let args := e.getAppArgs
let fNew := mkConst preDefsNew[funIdx]!.declName f.constLevels!
let fNew := mkAppN fNew args[:fixedPrefix]
let Expr.forallE _ d .. ← inferType fNew | unreachable!
let Expr.forallE _ d .. ← whnf (← inferType fNew) | unreachable!
-- NB: Use whnf in case the type is not a manifest forall, but a definition around it
let argNew ← mkUnaryArg d args[fixedPrefix:]
return mkApp fNew argNew
let rec

View file

@ -51,13 +51,13 @@ private partial def mkNewCoDomain (preDefsOriginal : Array PreDefinition) (preDe
let casesOn := mkAppN casesOn xTypeArgs -- parameters
let casesOn := mkApp casesOn (← mkLambdaFVars #[x] (mkSort u)) -- motive
let casesOn := mkApp casesOn x -- major
let minor1 ← withLocalDeclD (← mkFreshUserName `_x) xTypeArgs[0]! fun x =>
mkLambdaFVars #[x] (preDefTypes[i]!.bindingBody!.instantiate1 x)
let minor1 ← withLocalDeclD (← mkFreshUserName `_x) xTypeArgs[0]! fun x => do
mkLambdaFVars #[x] ((← whnf preDefTypes[i]!).bindingBody!.instantiate1 x)
let minor2 ← withLocalDeclD (← mkFreshUserName `_x) xTypeArgs[1]! fun x => do
mkLambdaFVars #[x] (← go x (i+1))
return mkApp2 casesOn minor1 minor2
else
return preDefTypes[i]!.bindingBody!.instantiate1 x
return (← whnf preDefTypes[i]!).bindingBody!.instantiate1 x
go x 0
/--
@ -176,7 +176,7 @@ where
def packMutual (fixedPrefix : Nat) (preDefsOriginal : Array PreDefinition) (preDefs : Array PreDefinition) : MetaM PreDefinition := do
if preDefs.size == 1 then return preDefs[0]!
withFixedPrefix fixedPrefix preDefs fun ys types vals => do
let domains := types.map fun type => type.bindingDomain!
let domains ← types.mapM fun type => do pure (← whnf type).bindingDomain!
let domain ← mkNewDomain domains
withLocalDeclD (← mkFreshUserName `_x) domain fun x => do
let codomain ← mkNewCoDomain preDefsOriginal types x

View file

@ -0,0 +1,15 @@
def FunType := Nat → Nat
def Fun2Type := Nat → Nat → Nat
mutual
def foo : FunType
| .zero => 0
| .succ n => bar n
def bar : Nat → Nat
| .zero => 0
| .succ n => baz n 0
def baz : Fun2Type
| .zero, m => 0
| .succ n, m => foo n
end
termination_by foo n => n; bar n => n; baz n _ => n