feat: better error message when constructor parameter universe level is too big

This commit is contained in:
Leonardo de Moura 2022-04-03 08:33:52 -07:00
parent ef8fecff79
commit 3ee8ceafb4
4 changed files with 64 additions and 7 deletions

View file

@ -1,6 +1,8 @@
Unreleased
---------
* Improve error message when constructor parameter universe level is too big.
* Add support for `for h : i in [start:stop] do .. ` where `h : i ∈ [start:stop]`. This feature is useful for proving
termination of functions such as:
```lean

View file

@ -392,17 +392,37 @@ def checkResultingUniverse (u : Level) : TermElabM Unit := do
if !u.isZero && !u.isNeverZero then
throwError "invalid universe polymorphic type, the resultant universe is not Prop (i.e., 0), but it may be Prop for some parameter values (solution: use 'u+1' or 'max 1 u'{indentD u}"
private def checkResultingUniverses (numParams : Nat) (indTypes : List InductiveType) : TermElabM Unit := do
let u ← getResultingUniverse indTypes
/--
Execute `k` using the `Syntax` reference associated with constructor `ctorName`.
-/
def withCtorRef (views : Array InductiveView) (ctorName : Name) (k : TermElabM α) : TermElabM α := do
for view in views do
for ctorView in view.ctors do
if ctorView.declName == ctorName then
return (← withRef ctorView.ref k)
k
private def checkResultingUniverses (views : Array InductiveView) (numParams : Nat) (indTypes : List InductiveType) : TermElabM Unit := do
let u ← instantiateLevelMVars (← getResultingUniverse indTypes)
checkResultingUniverse u
unless u.isZero do
indTypes.forM fun indType => indType.ctors.forM fun ctor =>
forallTelescopeReducing ctor.type fun ctorArgs type =>
for ctorArg in ctorArgs[numParams:] do
let v ← getLevel (← inferType ctorArg)
-- TODO
trace[Meta.debug] "checkCtorArgLevel, {v} <= {u}"
return ()
let type ← inferType ctorArg
let v ← instantiateLevelMVars (← getLevel type)
if v.hasMVar then
-- TODO
trace[Meta.debug] "checkCtorArgLevel, {v} <= {u}"
else unless u.geq v do
let mut msg := m!"invalid universe level in constructor '{ctor.name}', parameter"
let localDecl ← getFVarLocalDecl ctorArg
unless localDecl.userName.hasMacroScopes do
msg := msg ++ m!" '{ctorArg}'"
msg := msg ++ m!" has type{indentExpr type}"
msg := msg ++ m!"\nat universe level{indentD v}"
msg := msg ++ m!"\nit must be smaller than or equal to the inductive datatype universe level{indentD u}"
withCtorRef views ctor.name <| throwError msg
private def collectUsed (indTypes : List InductiveType) : StateRefT CollectFVars.State MetaM Unit := do
indTypes.forM fun indType => do
@ -602,7 +622,7 @@ private def mkInductiveDecl (vars : Array Expr) (views : Array InductiveView) :
if inferLevel then
updateResultingUniverse numParams (← levelMVarToParam indTypes)
else
checkResultingUniverses numParams indTypes
checkResultingUniverses views numParams indTypes
levelMVarToParam indTypes
let usedLevelNames := collectLevelParamsInInductive indTypes
match sortDeclLevelParams scopeLevelNames allUserLevelNames usedLevelNames with

View file

@ -0,0 +1,17 @@
inductive Bla : Type u where
| nil : Bla
| cons : (α : Type u) → (a : α) → Bla → Bla
inductive Foo : Type where
| leaf
| mk (α : Type) (a : α)
| mk₂
inductive Foo' : Type u where
| leaf
| mk : Sort (max u v) → a → Foo'
| mk₂
inductive Boo : Type u where
| nil : Boo
| cons : (α : Sort u) → (a : α) → Boo → Boo

View file

@ -0,0 +1,18 @@
ctorUnivTooBig.lean:3:2-3:45: error: invalid universe level in constructor 'Bla.cons', parameter 'α' has type
Type u
at universe level
u+2
it must be smaller than or equal to the inductive datatype universe level
u+1
ctorUnivTooBig.lean:7:2-7:25: error: invalid universe level in constructor 'Foo.mk', parameter 'α' has type
Type
at universe level
2
it must be smaller than or equal to the inductive datatype universe level
1
ctorUnivTooBig.lean:12:2-12:34: error: invalid universe level in constructor 'Foo'.mk', parameter has type
Sort (max u v)
at universe level
(max u v)+1
it must be smaller than or equal to the inductive datatype universe level
u+1