diff --git a/src/Lean/Elab/PreDefinition/Main.lean b/src/Lean/Elab/PreDefinition/Main.lean index 1559c6e987..059503f0e9 100644 --- a/src/Lean/Elab/PreDefinition/Main.lean +++ b/src/Lean/Elab/PreDefinition/Main.lean @@ -75,11 +75,14 @@ def addPreDefinitions (preDefs : Array PreDefinition) (terminationBy? : Option S addAndCompileUnsafe preDefs else if preDefs.any (·.modifiers.isPartial) then addAndCompilePartial preDefs + else if let some wfStx := terminationBy.find? (preDefs.map (·.declName)) then + terminationBy := terminationBy.erase (preDefs.map (·.declName)) + wfRecursion preDefs wfStx else - terminationBy ← withRef (preDefs[0].ref) <| mapError + withRef (preDefs[0].ref) <| mapError (orelseMergeErrors - (structuralRecursion preDefs *> pure terminationBy) - (wfRecursion preDefs terminationBy)) + (structuralRecursion preDefs) + (wfRecursion preDefs none)) (fun msg => let preDefMsgs := preDefs.toList.map (MessageData.ofExpr $ mkConst ·.declName) m!"fail to show termination for{indentD (MessageData.joinSep preDefMsgs Format.line)}\nwith errors\n{msg}") diff --git a/src/Lean/Elab/PreDefinition/WF/Main.lean b/src/Lean/Elab/PreDefinition/WF/Main.lean index eb36938d7e..df34eec805 100644 --- a/src/Lean/Elab/PreDefinition/WF/Main.lean +++ b/src/Lean/Elab/PreDefinition/WF/Main.lean @@ -7,12 +7,13 @@ import Lean.Elab.PreDefinition.Basic import Lean.Elab.PreDefinition.WF.TerminationBy import Lean.Elab.PreDefinition.WF.PackDomain import Lean.Elab.PreDefinition.WF.PackMutual +import Lean.Elab.PreDefinition.WF.Rel namespace Lean.Elab open WF open Meta -def wfRecursion (preDefs : Array PreDefinition) (terminationBy : TerminationBy) : TermElabM TerminationBy := do +def wfRecursion (preDefs : Array PreDefinition) (wfStx? : Option Syntax) : TermElabM Unit := do withoutModifyingEnv do for preDef in preDefs do addAsAxiom preDef @@ -22,7 +23,9 @@ def wfRecursion (preDefs : Array PreDefinition) (terminationBy : TerminationBy) trace[Elab.definition.wf] "{preDef.declName}, {preDef.levelParams}, {preDef.value}" let unaryPreDef ← packMutual unaryPreDefs trace[Elab.definition.wf] "{unaryPreDef.declName} := {unaryPreDef.value}" - check unaryPreDef.value + check unaryPreDef.value -- TODO: remove + let (wf, r) ← elabWF unaryPreDef wfStx? + trace[Elab.definition.wf] "{wf}" -- TODO throwError "well-founded recursion has not been implemented yet" diff --git a/src/Lean/Elab/PreDefinition/WF/Rel.lean b/src/Lean/Elab/PreDefinition/WF/Rel.lean new file mode 100644 index 0000000000..0349496d33 --- /dev/null +++ b/src/Lean/Elab/PreDefinition/WF/Rel.lean @@ -0,0 +1,29 @@ +/- +Copyright (c) 2021 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura +-/ +import Lean.Elab.SyntheticMVars +import Lean.Elab.PreDefinition.Basic + +namespace Lean.Elab.WF +open Meta +open Term + +def elabWF (unaryPreDef : PreDefinition) (wfStx? : Option Syntax) : TermElabM (Expr × Expr) := do + if let some wfStx := wfStx? then + withDeclName unaryPreDef.declName do + let α := unaryPreDef.type.bindingDomain! + let u ← getLevel α + let r ← mkFreshExprMVar (← mkArrow α (← mkArrow α (mkSort levelZero))) + let expectedType := mkApp2 (mkConst ``WellFounded [u]) α r + let w ← instantiateMVars (← withSynthesize <| elabTermEnsuringType wfStx expectedType) + let r ← instantiateMVars r + let pendingMVarIds ← getMVars w + discard <| logUnassignedUsingErrorInfos pendingMVarIds + return (r, w) + else + -- TODO: try to synthesize some default relation + throwError "'termination_by' modifier missing" + +end Lean.Elab.WF diff --git a/src/Lean/Elab/PreDefinition/WF/TerminationBy.lean b/src/Lean/Elab/PreDefinition/WF/TerminationBy.lean index 9aaa5d7f6c..9b703f169a 100644 --- a/src/Lean/Elab/PreDefinition/WF/TerminationBy.lean +++ b/src/Lean/Elab/PreDefinition/WF/TerminationBy.lean @@ -37,7 +37,7 @@ def expandTerminationBy (terminationBy? : Option Syntax) (cliques : Array (Array else return TerminationBy.none -def TerminatioBy.erase (t : TerminationBy) (clique : Array Name) : TerminationBy := +def TerminationBy.erase (t : TerminationBy) (clique : Array Name) : TerminationBy := match t with | TerminationBy.none => TerminationBy.none | TerminationBy.one .. => TerminationBy.none diff --git a/tests/lean/sanitychecks.lean.expected.out b/tests/lean/sanitychecks.lean.expected.out index e34c504bdb..858a9b738e 100644 --- a/tests/lean/sanitychecks.lean.expected.out +++ b/tests/lean/sanitychecks.lean.expected.out @@ -3,7 +3,7 @@ sanitychecks.lean:1:8-1:15: error: fail to show termination for with errors structural recursion cannot be used -well-founded recursion has not been implemented yet +'termination_by' modifier missing sanitychecks.lean:4:8-5:9: error: 'partial' theorems are not allowed, 'partial' is a code generation directive sanitychecks.lean:7:7-8:9: error: 'unsafe' theorems are not allowed sanitychecks.lean:10:0-10:24: error: failed to synthesize instance diff --git a/tests/lean/termination_by.lean b/tests/lean/termination_by.lean index 0aa90a62a0..5a817b5eef 100644 --- a/tests/lean/termination_by.lean +++ b/tests/lean/termination_by.lean @@ -13,21 +13,6 @@ mutual termination_by measure end -mutual - def f (n : Nat) := - match n with - | 0 => 1 - | n+1 => f n * 2 -end -termination_by measure - - -def g (n : Nat) := - match n with - | 0 => 1 - | n+1 => g n * 3 -termination_by measure - def g' (n : Nat) := match n with | 0 => 1 diff --git a/tests/lean/termination_by.lean.expected.out b/tests/lean/termination_by.lean.expected.out index e57f852439..9fd98fc7de 100644 --- a/tests/lean/termination_by.lean.expected.out +++ b/tests/lean/termination_by.lean.expected.out @@ -1,6 +1,4 @@ termination_by.lean:8:0-8:22: error: invalid 'termination_by' in mutually inductive datatype declaration termination_by.lean:13:1-13:23: error: invalid 'termination_by' in 'mutual' block, it must be used after the 'end' keyword -termination_by.lean:22:15-22:22: error: unused 'termination_by' element -termination_by.lean:29:15-29:22: error: unused 'termination_by' element -termination_by.lean:36:2-36:3: error: function 'h' not found in current declaration -termination_by.lean:54:7-54:14: error: invalid 'termination_by' element, 'Test.g' and 'Test.f' are in the same clique +termination_by.lean:21:2-21:3: error: function 'h' not found in current declaration +termination_by.lean:39:7-39:14: error: invalid 'termination_by' element, 'Test.g' and 'Test.f' are in the same clique