feat: elaborate emptyC notation

@Kha this is a little bit ugly. As in Lean3, the notation `{ }` is
overloaded. It can be `HasEmptyc.emptyc` or the empty structure.
Moreover, if we have an instance `HasEmptyc A` for a structure `A`,
then `{ }` is notation for `HasEmptyc.emptyc`. I am not very happy
about this, but it seems users use this feature. It is even used in
our own Lean4 code base :)

BTW, I will try a different alternative later.
First, move the notation `{ }` as a proper parser for `emptyc`.
Then, make sure the elaborator throws an error when
`{ }` is ambiguous. That is, `{}` can be elaborated as the empty
structure `A` and there is an `HasEmptyc A` instance.
Example:
```
structure A :=
(x : Nat := 0)

instance : HasEmptyc A :=
⟨{ x := 10 }⟩
```

The main issue here is that the support for choice+postpone is
currently broken.
This commit is contained in:
Leonardo de Moura 2020-09-11 10:42:39 -07:00
parent 32eabf2ef1
commit 1731962ea9
2 changed files with 49 additions and 5 deletions

View file

@ -773,6 +773,17 @@ else
let stxNew := stx.setArg 4 mkNullNode;
`(($stxNew : $expected))
private def isEmptyStructInst (stx : Syntax) : Bool :=
(stx.getArg 1).isNone &&
(stx.getArg 2).isNone &&
(stx.getArg 3).isNone &&
(stx.getArg 4).isNone
@[builtinTermElab emptyC] def expandEmptyC : TermElab :=
fun stx expectedType? => do
stxNew ← `(HasEmptyc.emptyc);
withMacroExpansion stx stxNew $ elabTerm stxNew expectedType?
@[builtinTermElab structInst] def elabStructInst : TermElab :=
fun stx expectedType? => do
stxNew? ← liftMacroM $ expandStructInstExpectedType stx;
@ -784,11 +795,22 @@ fun stx expectedType? => do
| some stxNew => withMacroExpansion stx stxNew $ elabTerm stxNew expectedType?
| none => do
sourceView ← getStructSource stx;
modifyOp? ← isModifyOp? stx;
match modifyOp?, sourceView with
| some modifyOp, Source.explicit source _ => elabModifyOp stx modifyOp source expectedType?
| some _, _ => throwError ("invalid {...} notation, explicit source is required when using '[<index>] := <value>'")
| _, _ => elabStructInstAux stx expectedType? sourceView
if isEmptyStructInst stx then do
/- Recall that we also want to use `{}` as notation for `HasEmptyc.emptyc` -/
tryPostponeIfNoneOrMVar expectedType?;
match expectedType? with
| none => expandEmptyC stx expectedType?
| some expectedType =>
/- We first try to create `@HasEmptyc.emptyc expectedType _`, if it fails, we elaborate as the empty structure. -/
catch
(mkAppOptM `HasEmptyc.emptyc #[expectedType, none])
(fun _ => elabStructInstAux stx expectedType? sourceView)
else do
modifyOp? ← isModifyOp? stx;
match modifyOp?, sourceView with
| some modifyOp, Source.explicit source _ => elabModifyOp stx modifyOp source expectedType?
| some _, _ => throwError ("invalid {...} notation, explicit source is required when using '[<index>] := <value>'")
| _, _ => elabStructInstAux stx expectedType? sourceView
@[init] private def regTraceClasses : IO Unit := do
registerTraceClass `Elab.struct;

View file

@ -0,0 +1,22 @@
new_frontend
structure A :=
(x : Nat := 0)
def foo : A :=
{}
theorem ex1 : foo = { x := 0 } :=
rfl
theorem ex2 : foo.x = 0 :=
rfl
instance : HasEmptyc A :=
⟨{ x := 10 }⟩
def boo : A :=
{} -- this HasEmptyc.emptyc
theorem ex3 : boo.x = 10 :=
rfl