feat: extract delabAppCore, define withOverApp, and make over-applied projections pretty print (#3083)
To handle delaborating notations that are functions that can be applied to arguments, extracts the core function application delaborator as a separate function that accepts the number of arguments to process and a delaborator to apply to the "head" of the expression. Defines `withOverApp`, which has the same interface as the combinator of the same name from std4, but it uses this core function application delaborator. Uses `withOverApp` to improve a number of application delaborators, notably projections. This means Mathlib can stop using `pp_dot` for structure fields that have function types. Incidentally fixes `getParamKinds` to specialize default values to use supplied arguments, which impacts how default arguments are delaborated. --------- Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
This commit is contained in:
parent
9069c538ad
commit
c394a834c3
11 changed files with 265 additions and 103 deletions
|
|
@ -919,6 +919,17 @@ private def getAppNumArgsAux : Expr → Nat → Nat
|
|||
def getAppNumArgs (e : Expr) : Nat :=
|
||||
getAppNumArgsAux e 0
|
||||
|
||||
/--
|
||||
Like `Lean.Expr.getAppFn` but assumes the application has up to `maxArgs` arguments.
|
||||
If there are any more arguments than this, then they are returned by `getAppFn` as part of the function.
|
||||
|
||||
In particular, if the given expression is a sequence of function applications `f a₁ .. aₙ`,
|
||||
returns `f a₁ .. aₖ` where `k` is minimal such that `n - k ≤ maxArgs`.
|
||||
-/
|
||||
def getBoundedAppFn : (maxArgs : Nat) → Expr → Expr
|
||||
| maxArgs' + 1, .app f _ => getBoundedAppFn maxArgs' f
|
||||
| _, e => e
|
||||
|
||||
private def getAppArgsAux : Expr → Array Expr → Nat → Array Expr
|
||||
| app f a, as, i => getAppArgsAux f (as.set! i a) (i-1)
|
||||
| _, as, _ => as
|
||||
|
|
@ -929,6 +940,21 @@ private def getAppArgsAux : Expr → Array Expr → Nat → Array Expr
|
|||
let nargs := e.getAppNumArgs
|
||||
getAppArgsAux e (mkArray nargs dummy) (nargs-1)
|
||||
|
||||
private def getBoundedAppArgsAux : Expr → Array Expr → Nat → Array Expr
|
||||
| app f a, as, i + 1 => getBoundedAppArgsAux f (as.set! i a) i
|
||||
| _, as, _ => as
|
||||
|
||||
/--
|
||||
Like `Lean.Expr.getAppArgs` but returns up to `maxArgs` arguments.
|
||||
|
||||
In particular, given `f a₁ a₂ ... aₙ`, returns `#[aₖ₊₁, ..., aₙ]`
|
||||
where `k` is minimal such that the size of this array is at most `maxArgs`.
|
||||
-/
|
||||
@[inline] def getBoundedAppArgs (maxArgs : Nat) (e : Expr) : Array Expr :=
|
||||
let dummy := mkSort levelZero
|
||||
let nargs := min maxArgs e.getAppNumArgs
|
||||
getBoundedAppArgsAux e (mkArray nargs dummy) nargs
|
||||
|
||||
private def getAppRevArgsAux : Expr → Array Expr → Array Expr
|
||||
| app f a, as => getAppRevArgsAux f (as.push a)
|
||||
| _, as => as
|
||||
|
|
|
|||
|
|
@ -104,72 +104,94 @@ def delabAppFn : Delab := do
|
|||
else
|
||||
delab
|
||||
|
||||
/--
|
||||
A structure that records details of a function parameter.
|
||||
-/
|
||||
structure ParamKind where
|
||||
/-- Binder name for the parameter. -/
|
||||
name : Name
|
||||
/-- Binder info for the parameter. -/
|
||||
bInfo : BinderInfo
|
||||
/-- The default value for the parameter, if the parameter has a default value. -/
|
||||
defVal : Option Expr := none
|
||||
/-- Whether the parameter is an autoparam (i.e., whether it uses a tactic for the default value). -/
|
||||
isAutoParam : Bool := false
|
||||
|
||||
/--
|
||||
Returns true if the parameter is an explicit parameter that has neither a default value nor a tactic.
|
||||
-/
|
||||
def ParamKind.isRegularExplicit (param : ParamKind) : Bool :=
|
||||
param.bInfo.isExplicit && !param.isAutoParam && param.defVal.isNone
|
||||
|
||||
/-- Return array with n-th element set to kind of n-th parameter of `e`. -/
|
||||
partial def getParamKinds : DelabM (Array ParamKind) := do
|
||||
let e ← getExpr
|
||||
/--
|
||||
Given a function `f` supplied with arguments `args`, returns an array whose n-th element
|
||||
is set to the kind of the n-th argument's associated parameter.
|
||||
We do not assume the expression `mkAppN f args` is sensical,
|
||||
and this function captures errors (except for panics) and returns the empty array.
|
||||
|
||||
The returned array might be longer than the number of arguments.
|
||||
It gives parameter kinds for the fully-applied function.
|
||||
Note: the `defVal` expressions are only guaranteed to be valid for parameters associated to the supplied arguments;
|
||||
after this, they might refer to temporary fvars.
|
||||
|
||||
This function properly handles "overapplied" functions.
|
||||
For example, while `id` takes one explicit argument, it can take more than one explicit
|
||||
argument when its arguments are specialized to function types, like in `id id 2`.
|
||||
-/
|
||||
def getParamKinds (f : Expr) (args : Array Expr) : MetaM (Array ParamKind) := do
|
||||
try
|
||||
withTransparency TransparencyMode.all do
|
||||
forallTelescopeArgs e.getAppFn e.getAppArgs fun params _ => do
|
||||
params.mapM fun param => do
|
||||
let l ← param.fvarId!.getDecl
|
||||
pure { name := l.userName, bInfo := l.binderInfo, defVal := l.type.getOptParamDefault?, isAutoParam := l.type.isAutoParam }
|
||||
let mut result : Array ParamKind := Array.mkEmpty args.size
|
||||
let mut fnType ← inferType f
|
||||
let mut j := 0
|
||||
for i in [0:args.size] do
|
||||
unless fnType.isForall do
|
||||
fnType ← whnf (fnType.instantiateRevRange j i args)
|
||||
j := i
|
||||
let .forallE n t b bi := fnType | failure
|
||||
let defVal := t.getOptParamDefault? |>.map (·.instantiateRevRange j i args)
|
||||
result := result.push { name := n, bInfo := bi, defVal, isAutoParam := t.isAutoParam }
|
||||
fnType := b
|
||||
fnType := fnType.instantiateRevRange j args.size args
|
||||
-- We still want to consider parameters past the ones for the supplied arguments.
|
||||
forallTelescopeReducing fnType fun xs _ => do
|
||||
xs.foldlM (init := result) fun result x => do
|
||||
let l ← x.fvarId!.getDecl
|
||||
-- Warning: the defVal might refer to fvars that are only valid in this context
|
||||
pure <| result.push { name := l.userName, bInfo := l.binderInfo, defVal := l.type.getOptParamDefault?, isAutoParam := l.type.isAutoParam }
|
||||
catch _ => pure #[] -- recall that expr may be nonsensical
|
||||
where
|
||||
forallTelescopeArgs f args k := do
|
||||
forallBoundedTelescope (← inferType f) args.size fun xs b =>
|
||||
if xs.isEmpty || xs.size == args.size then
|
||||
-- we still want to consider optParams
|
||||
forallTelescopeReducing b fun ys b => k (xs ++ ys) b
|
||||
else
|
||||
forallTelescopeArgs (mkAppN f $ args.shrink xs.size) (args.extract xs.size args.size) fun ys b =>
|
||||
k (xs ++ ys) b
|
||||
|
||||
@[builtin_delab app]
|
||||
def delabAppExplicit : Delab := do
|
||||
let paramKinds ← getParamKinds
|
||||
let tagAppFn ← getPPOption getPPTagAppFns
|
||||
let (fnStx, _, argStxs) ← withAppFnArgs
|
||||
(do
|
||||
let stx ← withOptionAtCurrPos `pp.tagAppFns tagAppFn delabAppFn
|
||||
let needsExplicit := stx.raw.getKind != ``Lean.Parser.Term.explicit
|
||||
let stx ← if needsExplicit then `(@$stx) else pure stx
|
||||
pure (stx, paramKinds.toList, #[]))
|
||||
(fun ⟨fnStx, paramKinds, argStxs⟩ => do
|
||||
let isInstImplicit := match paramKinds with
|
||||
| [] => false
|
||||
| param :: _ => param.bInfo == BinderInfo.instImplicit
|
||||
let argStx ← if ← getPPOption getPPAnalysisHole then `(_)
|
||||
else if isInstImplicit == true then
|
||||
let stx ← if ← getPPOption getPPInstances then delab else `(_)
|
||||
if ← getPPOption getPPInstanceTypes then
|
||||
let typeStx ← withType delab
|
||||
`(($stx : $typeStx))
|
||||
else pure stx
|
||||
else delab
|
||||
pure (fnStx, paramKinds.tailD [], argStxs.push argStx))
|
||||
return Syntax.mkApp fnStx argStxs
|
||||
|
||||
def shouldShowMotive (motive : Expr) (opts : Options) : MetaM Bool := do
|
||||
pure (getPPMotivesAll opts)
|
||||
<||> (pure (getPPMotivesPi opts) <&&> returnsPi motive)
|
||||
<||> (pure (getPPMotivesNonConst opts) <&&> isNonConstFun motive)
|
||||
|
||||
def isRegularApp : DelabM Bool := do
|
||||
/--
|
||||
Returns true if an application should use explicit mode when delaborating.
|
||||
-/
|
||||
def useAppExplicit (paramKinds : Array ParamKind) : DelabM Bool := do
|
||||
if ← getPPOption getPPExplicit then
|
||||
if paramKinds.any (fun param => !param.isRegularExplicit) then return true
|
||||
|
||||
-- If the expression has an implicit function type, fall back to delabAppExplicit.
|
||||
-- This is e.g. necessary for `@Eq`.
|
||||
let isImplicitApp ← try
|
||||
let ty ← whnf (← inferType (← getExpr))
|
||||
pure <| ty.isForall && (ty.binderInfo matches .implicit | .instImplicit)
|
||||
catch _ => pure false
|
||||
if isImplicitApp then return true
|
||||
|
||||
return false
|
||||
|
||||
/--
|
||||
Returns true if the application is a candidate for unexpanders.
|
||||
-/
|
||||
def isRegularApp (maxArgs : Nat) : DelabM Bool := do
|
||||
let e ← getExpr
|
||||
if not (unfoldMDatas e.getAppFn).isConst then return false
|
||||
if ← withNaryFn (withMDatasOptions (getPPOption getPPUniverses <||> getPPOption getPPAnalysisBlockImplicit)) then return false
|
||||
for i in [:e.getAppNumArgs] do
|
||||
if ← withNaryArg i (getPPOption getPPAnalysisNamedArg) then return false
|
||||
return true
|
||||
if not (unfoldMDatas (e.getBoundedAppFn maxArgs)).isConst then return false
|
||||
withBoundedAppFnArgs maxArgs
|
||||
(not <$> withMDatasOptions (getPPOption getPPUniverses <||> getPPOption getPPAnalysisBlockImplicit))
|
||||
(fun b => pure b <&&> not <$> getPPOption getPPAnalysisNamedArg)
|
||||
|
||||
def unexpandRegularApp (stx : Syntax) : Delab := do
|
||||
let Expr.const c .. := (unfoldMDatas (← getExpr).getAppFn) | unreachable!
|
||||
|
|
@ -204,25 +226,42 @@ def unexpandStructureInstance (stx : Syntax) : Delab := whenPPOption getPPStruct
|
|||
if (← getPPOption getPPStructureInstanceType) then delab >>= pure ∘ some else pure none
|
||||
`({ $fields,* $[: $tyStx]? })
|
||||
|
||||
@[builtin_delab app]
|
||||
def delabAppImplicit : Delab := do
|
||||
/--
|
||||
Delaborates a function application in explicit mode, and ensures the resulting
|
||||
head syntax is wrapped with `@`.
|
||||
-/
|
||||
def delabAppExplicitCore (maxArgs : Nat) (delabHead : Delab) (paramKinds : Array ParamKind) (tagAppFn : Bool) : Delab := do
|
||||
let (fnStx, _, argStxs) ← withBoundedAppFnArgs maxArgs
|
||||
(do
|
||||
let stx ← withOptionAtCurrPos `pp.tagAppFns tagAppFn delabHead
|
||||
let needsExplicit := stx.raw.getKind != ``Lean.Parser.Term.explicit
|
||||
let stx ← if needsExplicit then `(@$stx) else pure stx
|
||||
pure (stx, paramKinds.toList, #[]))
|
||||
(fun ⟨fnStx, paramKinds, argStxs⟩ => do
|
||||
let isInstImplicit := match paramKinds with
|
||||
| [] => false
|
||||
| param :: _ => param.bInfo == BinderInfo.instImplicit
|
||||
let argStx ← if ← getPPOption getPPAnalysisHole then `(_)
|
||||
else if isInstImplicit == true then
|
||||
let stx ← if ← getPPOption getPPInstances then delab else `(_)
|
||||
if ← getPPOption getPPInstanceTypes then
|
||||
let typeStx ← withType delab
|
||||
`(($stx : $typeStx))
|
||||
else pure stx
|
||||
else delab
|
||||
pure (fnStx, paramKinds.tailD [], argStxs.push argStx))
|
||||
return Syntax.mkApp fnStx argStxs
|
||||
|
||||
/--
|
||||
Delaborates a function application in the standard mode, where implicit arguments are generally not
|
||||
included.
|
||||
-/
|
||||
def delabAppImplicitCore (maxArgs : Nat) (delabHead : Delab) (paramKinds : Array ParamKind) (tagAppFn : Bool) : Delab := do
|
||||
-- TODO: always call the unexpanders, make them guard on the right # args?
|
||||
let paramKinds ← getParamKinds
|
||||
if ← getPPOption getPPExplicit then
|
||||
if paramKinds.any (fun param => !param.isRegularExplicit) then failure
|
||||
|
||||
-- If the application has an implicit function type, fall back to delabAppExplicit.
|
||||
-- This is e.g. necessary for `@Eq`.
|
||||
let isImplicitApp ← try
|
||||
let ty ← whnf (← inferType (← getExpr))
|
||||
pure <| ty.isForall && (ty.binderInfo == BinderInfo.implicit || ty.binderInfo == BinderInfo.instImplicit)
|
||||
catch _ => pure false
|
||||
if isImplicitApp then failure
|
||||
|
||||
let tagAppFn ← getPPOption getPPTagAppFns
|
||||
let (fnStx, _, argStxs) ← withAppFnArgs
|
||||
(withOptionAtCurrPos `pp.tagAppFns tagAppFn <|
|
||||
return (← delabAppFn, paramKinds.toList, #[]))
|
||||
let (fnStx, _, argStxs) ← withBoundedAppFnArgs maxArgs
|
||||
(do
|
||||
let stx ← withOptionAtCurrPos `pp.tagAppFns tagAppFn delabHead
|
||||
return (stx, paramKinds.toList, #[]))
|
||||
(fun (fnStx, paramKinds, argStxs) => do
|
||||
let arg ← getExpr
|
||||
let opts ← getOptions
|
||||
|
|
@ -247,12 +286,60 @@ def delabAppImplicit : Delab := do
|
|||
pure (fnStx, paramKinds.tailD [], argStxs))
|
||||
let stx := Syntax.mkApp fnStx argStxs
|
||||
|
||||
if ← isRegularApp then
|
||||
if ← isRegularApp maxArgs then
|
||||
(guard (← getPPOption getPPNotation) *> unexpandRegularApp stx)
|
||||
<|> (guard (← getPPOption getPPStructureInstances) *> unexpandStructureInstance stx)
|
||||
<|> pure stx
|
||||
else pure stx
|
||||
|
||||
/--
|
||||
Delaborates applications. Removes up to `maxArgs` arguments to form
|
||||
the "head" of the application and delaborates the head using `delabHead`.
|
||||
The remaining arguments are processed depending on whether heuristics indicate that the application
|
||||
should be delaborated using `@`.
|
||||
-/
|
||||
def delabAppCore (maxArgs : Nat) (delabHead : Delab) : Delab := do
|
||||
let tagAppFn ← getPPOption getPPTagAppFns
|
||||
let e ← getExpr
|
||||
let paramKinds ← getParamKinds (e.getBoundedAppFn maxArgs) (e.getBoundedAppArgs maxArgs)
|
||||
|
||||
let useExplicit ← useAppExplicit paramKinds
|
||||
|
||||
if useExplicit then
|
||||
delabAppExplicitCore maxArgs delabHead paramKinds tagAppFn
|
||||
else
|
||||
delabAppImplicitCore maxArgs delabHead paramKinds tagAppFn
|
||||
|
||||
/--
|
||||
Default delaborator for applications.
|
||||
-/
|
||||
@[builtin_delab app]
|
||||
def delabApp : Delab := do
|
||||
delabAppCore (← getExpr).getAppNumArgs delabAppFn
|
||||
|
||||
/--
|
||||
The `withOverApp` combinator allows delaborators to handle "over-application" by using the core
|
||||
application delaborator to handle additional arguments.
|
||||
|
||||
For example, suppose `f : {A : Type} → Foo A → A` and we want to implement a delaborator for
|
||||
applications `f x` to pretty print as `F[x]`. Because `A` is a type variable we might encounter
|
||||
a term of the form `@f (A → B) x y`, which has an additional argument `y`.
|
||||
With this combinator one can use an arity-2 delaborator to pretty print this as `F[x] y`.
|
||||
|
||||
* `arity`: the expected number of arguments to `f`.
|
||||
The combinator will fail if fewer than this number of arguments are passed,
|
||||
and if more than this number of arguments are passed the arguments are handled using
|
||||
the standard application delaborator.
|
||||
* `x`: constructs data corresponding to the main application (`f x` in the example)
|
||||
-/
|
||||
def withOverApp (arity : Nat) (x : Delab) : Delab := do
|
||||
let n := (← getExpr).getAppNumArgs
|
||||
guard <| n ≥ arity
|
||||
if n == arity then
|
||||
x
|
||||
else
|
||||
delabAppCore (n - arity) x
|
||||
|
||||
/-- State for `delabAppMatch` and helpers. -/
|
||||
structure AppMatchState where
|
||||
info : MatcherInfo
|
||||
|
|
@ -394,25 +481,12 @@ def delabAppMatch : Delab := whenPPOption getPPNotation <| whenPPOption getPPMat
|
|||
`(match $[$st.discrs:matchDiscr],* with $[| $pats,* => $st.rhss]*)
|
||||
return Syntax.mkApp stx st.moreArgs
|
||||
|
||||
/--
|
||||
Annotation key to use in hack for overapplied `let_fun` notation.
|
||||
-/
|
||||
def delabLetFunKey : Name := `_delabLetFun
|
||||
|
||||
/--
|
||||
Delaborates applications of the form `letFun v (fun x => b)` as `let_fun x := v; b`.
|
||||
-/
|
||||
@[builtin_delab app.letFun]
|
||||
def delabLetFun : Delab := whenPPOption getPPNotation do
|
||||
def delabLetFun : Delab := whenPPOption getPPNotation <| withOverApp 4 do
|
||||
let e ← getExpr
|
||||
let nargs := e.getAppNumArgs
|
||||
if 4 < nargs then
|
||||
-- It's overapplied. Hack: insert metadata around the first four arguments and delaborate again.
|
||||
-- This will cause the app delaborator to delaborate `(letFun v f) x1 ... xn` with `letFun v f` as the function.
|
||||
let args := e.getAppArgs
|
||||
let f := mkAppN e.getAppFn (args.extract 0 4)
|
||||
let e' := mkAppN (mkAnnotation delabLetFunKey f) (args.extract 4 args.size)
|
||||
return (← withTheReader SubExpr ({· with expr := e'}) delab)
|
||||
guard <| e.getAppNumArgs == 4
|
||||
let Expr.lam n _ b _ := e.appArg! | failure
|
||||
let n ← getUnusedName n b
|
||||
|
|
@ -611,13 +685,13 @@ def delabLit : Delab := do
|
|||
|
||||
-- `@OfNat.ofNat _ n _` ~> `n`
|
||||
@[builtin_delab app.OfNat.ofNat]
|
||||
def delabOfNat : Delab := whenPPOption getPPCoercions do
|
||||
def delabOfNat : Delab := whenPPOption getPPCoercions <| withOverApp 3 do
|
||||
let .app (.app _ (.lit (.natVal n))) _ ← getExpr | failure
|
||||
return quote n
|
||||
|
||||
-- `@OfDecimal.ofDecimal _ _ m s e` ~> `m*10^(sign * e)` where `sign == 1` if `s = false` and `sign = -1` if `s = true`
|
||||
@[builtin_delab app.OfScientific.ofScientific]
|
||||
def delabOfScientific : Delab := whenPPOption getPPCoercions do
|
||||
def delabOfScientific : Delab := whenPPOption getPPCoercions <| withOverApp 5 do
|
||||
let expr ← getExpr
|
||||
guard <| expr.getAppNumArgs == 5
|
||||
let .lit (.natVal m) ← pure (expr.getArg! 2) | failure
|
||||
|
|
@ -654,24 +728,23 @@ def delabProj : Delab := do
|
|||
/-- Delaborate a call to a projection function such as `Prod.fst`. -/
|
||||
@[builtin_delab app]
|
||||
def delabProjectionApp : Delab := whenPPOption getPPStructureProjections $ do
|
||||
let e@(Expr.app fn _) ← getExpr | failure
|
||||
let Expr.app fn _ ← getExpr | failure
|
||||
let .const c@(.str _ f) _ ← pure fn.getAppFn | failure
|
||||
let env ← getEnv
|
||||
let some info ← pure $ env.getProjectionFnInfo? c | failure
|
||||
-- can't use with classes since the instance parameter is implicit
|
||||
guard $ !info.fromClass
|
||||
-- projection function should be fully applied (#struct params + 1 instance parameter)
|
||||
-- TODO: support over-application
|
||||
guard $ e.getAppNumArgs == info.numParams + 1
|
||||
-- If pp.explicit is true, and the structure has parameters, we should not
|
||||
-- use field notation because we will not be able to see the parameters.
|
||||
let expl ← getPPOption getPPExplicit
|
||||
guard $ !expl || info.numParams == 0
|
||||
let appStx ← withAppArg delab
|
||||
`($(appStx).$(mkIdent f):ident)
|
||||
-- projection function should be fully applied (#struct params + 1 instance parameter)
|
||||
withOverApp (info.numParams + 1) do
|
||||
let appStx ← withAppArg delab
|
||||
`($(appStx).$(mkIdent f):ident)
|
||||
|
||||
@[builtin_delab app.dite]
|
||||
def delabDIte : Delab := whenPPOption getPPNotation do
|
||||
def delabDIte : Delab := whenPPOption getPPNotation <| withOverApp 5 do
|
||||
-- Note: we keep this as a delaborator for now because it actually accesses the expression.
|
||||
guard $ (← getExpr).getAppNumArgs == 5
|
||||
let c ← withAppFn $ withAppFn $ withAppFn $ withAppArg delab
|
||||
|
|
@ -688,7 +761,7 @@ where
|
|||
return (← delab, h.getId)
|
||||
|
||||
@[builtin_delab app.cond]
|
||||
def delabCond : Delab := whenPPOption getPPNotation do
|
||||
def delabCond : Delab := whenPPOption getPPNotation <| withOverApp 4 do
|
||||
guard $ (← getExpr).getAppNumArgs == 4
|
||||
let c ← withAppFn $ withAppFn $ withAppArg delab
|
||||
let t ← withAppFn $ withAppArg delab
|
||||
|
|
|
|||
|
|
@ -42,12 +42,28 @@ def withAppArg (x : m α) : m α := do descend (← getExpr).appArg! 1 x
|
|||
def withType (x : m α) : m α := do
|
||||
descend (← Meta.inferType (← getExpr)) Pos.typeCoord x -- phantom positions for types
|
||||
|
||||
/--
|
||||
Uses `xa` to compute the fold across the arguments of an application,
|
||||
where `xf` provides the initial value and is evaluated in the context of the head of the application.
|
||||
-/
|
||||
partial def withAppFnArgs (xf : m α) (xa : α → m α) : m α := do
|
||||
if (← getExpr).isApp then
|
||||
let acc ← withAppFn (withAppFnArgs xf xa)
|
||||
withAppArg (xa acc)
|
||||
else xf
|
||||
|
||||
/--
|
||||
Uses `xa` to compute the fold across up to `maxArgs` outermost arguments of an application,
|
||||
where `xf` provides the initial value and is evaluated in the context of the application minus
|
||||
the arguments being folded across.
|
||||
-/
|
||||
def withBoundedAppFnArgs (maxArgs : Nat) (xf : m α) (xa : α → m α) : m α := do
|
||||
match maxArgs, (← getExpr) with
|
||||
| maxArgs' + 1, .app .. =>
|
||||
let acc ← withAppFn (withBoundedAppFnArgs maxArgs' xf xa)
|
||||
withAppArg (xa acc)
|
||||
| _, _ => xf
|
||||
|
||||
def withBindingDomain (x : m α) : m α := do descend (← getExpr).bindingDomain! 0 x
|
||||
|
||||
def withBindingBody (n : Name) (x : m α) : m α := do
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ def ppExprTagged (e : Expr) (explicit : Bool := false) : MetaM CodeWithInfos :=
|
|||
if explicit then
|
||||
withOptionAtCurrPos pp.tagAppFns.name true do
|
||||
withOptionAtCurrPos pp.explicit.name true do
|
||||
delabAppImplicit <|> delabAppExplicit
|
||||
delabApp
|
||||
else
|
||||
delab
|
||||
let ⟨fmt, infos⟩ ← PrettyPrinter.ppExprWithInfos e (delab := delab)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
283.lean:1:24-1:25: error: application type mismatch
|
||||
f (f ?m)
|
||||
f f
|
||||
argument
|
||||
f ?m
|
||||
f
|
||||
has type
|
||||
?m : Sort ?u
|
||||
but is expected to have type
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
fn.imp : {p : P} → Bar.fn p
|
||||
439.lean:18:7-18:12: error: function expected at
|
||||
Fn.imp fn
|
||||
fn.imp
|
||||
term has type
|
||||
Bar.fn ?m
|
||||
439.lean:29:7-29:11: error: function expected at
|
||||
Fn.imp fn
|
||||
fn.imp
|
||||
term has type
|
||||
Bar.fn ?m
|
||||
Fn.imp fn : Bar.fn p
|
||||
Fn.imp fn' Bp : Bar.fn p
|
||||
fn.imp : Bar.fn p
|
||||
fn'.imp Bp : Bar.fn p
|
||||
439.lean:39:11-39:12: error: application type mismatch
|
||||
Fn.imp fn' p
|
||||
fn'.imp p
|
||||
argument
|
||||
p
|
||||
has type
|
||||
P : Sort u
|
||||
but is expected to have type
|
||||
Bar.fn ?m : Sort ?u
|
||||
Fn.imp fn' (sorryAx (Bar.fn ?m) true) : Bar.fn ?m
|
||||
fn'.imp (sorryAx (Bar.fn ?m) true) : Bar.fn ?m
|
||||
|
|
|
|||
39
tests/lean/delabApp.lean
Normal file
39
tests/lean/delabApp.lean
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/-!
|
||||
# Testing features of the app delaborator, including overapplication
|
||||
-/
|
||||
|
||||
/-!
|
||||
Check that the optional value equality check is specialized to the supplied arguments
|
||||
(rather than, formerly, the locally-defined fvars from a telescope).
|
||||
-/
|
||||
def foo (α : Type) [Inhabited α] (x : α := default) : α := x
|
||||
|
||||
#check foo Nat
|
||||
#check foo Nat 1
|
||||
|
||||
/-!
|
||||
Check that overapplied projections pretty print using projection notation.
|
||||
-/
|
||||
|
||||
structure Foo where
|
||||
f : Nat → Nat
|
||||
|
||||
#check ∀ (x : Foo), x.f 1 = 0
|
||||
|
||||
/-!
|
||||
Overapplied `letFun`
|
||||
-/
|
||||
#check (have f := id; f) 1
|
||||
|
||||
/-!
|
||||
Overapplied `OfNat.ofNat`
|
||||
-/
|
||||
instance : OfNat (Nat → Nat) 1 where
|
||||
ofNat := id
|
||||
|
||||
#check (1 : Nat → Nat) 2
|
||||
|
||||
/-!
|
||||
Overapplied `dite`
|
||||
-/
|
||||
#check (if h : True then id else id) 1
|
||||
8
tests/lean/delabApp.lean.expected.out
Normal file
8
tests/lean/delabApp.lean.expected.out
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
foo Nat : Nat
|
||||
foo Nat 1 : Nat
|
||||
∀ (x : Foo), x.f 1 = 0 : Prop
|
||||
(let_fun f := id;
|
||||
f)
|
||||
1 : Nat
|
||||
1 2 : Nat
|
||||
(if h : True then id else id) 1 : Nat
|
||||
|
|
@ -9,4 +9,4 @@ fun (a : Nat) =>
|
|||
(@Eq.{1} Bool (@bne.{0} Nat instBEqNat a (@OfNat.ofNat.{0} Nat 1 (instOfNatNat 1))) Bool.true)
|
||||
(@Eq.{1} Bool (@bne.{0} Nat instBEqNat a (@OfNat.ofNat.{0} Nat 2 (instOfNatNat 2))) Bool.true)
|
||||
def s : Option Nat :=
|
||||
HOrElse.hOrElse (ConstantFunction.f myFun 3) fun x => ConstantFunction.f myFun 4
|
||||
HOrElse.hOrElse (myFun.f 3) fun x => myFun.f 4
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ fun x x_1 =>
|
|||
(fun x f x_2 =>
|
||||
(match x_2, x with
|
||||
| a, Nat.zero => fun x => a
|
||||
| a, Nat.succ b => fun x => Nat.succ (PProd.fst x.fst a))
|
||||
| a, Nat.succ b => fun x => Nat.succ (x.fst.fst a))
|
||||
f)
|
||||
x
|
||||
protected def Nat.add : Nat → Nat → Nat :=
|
||||
|
|
@ -13,7 +13,7 @@ fun x x_1 =>
|
|||
(fun x f x_2 =>
|
||||
(match (motive := Nat → (x : Nat) → Nat.below (motive := fun x => Nat → Nat) x → Nat) x_2, x with
|
||||
| a, Nat.zero => fun x => a
|
||||
| a, Nat.succ b => fun x => Nat.succ (PProd.fst x.fst a))
|
||||
| a, Nat.succ b => fun x => Nat.succ (x.fst.fst a))
|
||||
f)
|
||||
x
|
||||
theorem ex.{u} : ∀ {α β : Sort u} (h : α = β) (a : α), HEq (cast h a) a :=
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
sorryAtError.lean:13:46-13:47: error: application type mismatch
|
||||
Ty.ty ty Γ
|
||||
ty.ty Γ
|
||||
argument
|
||||
Γ
|
||||
has type
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue