The new folder will contain the new parser, macro expander and compiler. This commit also renames the namespace for the old parser `lean3.parser`
88 lines
3.8 KiB
Text
88 lines
3.8 KiB
Text
/-
|
|
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Sebastian Ullrich
|
|
|
|
Attribute that can automatically derive typeclass instances.
|
|
-/
|
|
prelude
|
|
import init.meta.attribute
|
|
import init.meta.interactive_base
|
|
import init.meta.mk_has_reflect_instance
|
|
|
|
open lean3
|
|
open interactive.types
|
|
open tactic
|
|
|
|
/-- A handler that may or may not be able to implement the typeclass `cls` for `decl`.
|
|
It should return `tt` if it was able to derive `cls` and `ff` if it does not know
|
|
how to derive `cls`, in which case lower-priority handlers will be tried next. -/
|
|
meta def derive_handler := Π (cls : pexpr) (decl : name), tactic bool
|
|
|
|
@[user_attribute]
|
|
meta def derive_handler_attr : user_attribute :=
|
|
{ name := `derive_handler, descr := "register a definition of type `derive_handler` for use in the [derive] attribute" }
|
|
|
|
private meta def try_handlers (p : pexpr) (n : name) : list derive_handler → tactic unit
|
|
| [] := fail format!"failed to find a derive handler for '{p}'"
|
|
| (h::hs) :=
|
|
do success ← h p n,
|
|
when (¬success) $
|
|
try_handlers hs
|
|
|
|
@[user_attribute] meta def derive_attr : user_attribute unit (list pexpr) :=
|
|
{ name := `derive, descr := "automatically derive typeclass instances",
|
|
parser := pexpr_list_or_texpr,
|
|
after_set := some (λ n _ _,
|
|
do ps ← derive_attr.get_param n,
|
|
handlers ← attribute.get_instances `derive_handler,
|
|
handlers ← handlers.mmap (λ n, eval_expr derive_handler (expr.const n [])),
|
|
ps.mmap' (λ p, try_handlers p n handlers)) }
|
|
|
|
/-- Given a tactic `tac` that can solve an application of `cls` in the right context,
|
|
`instance_derive_handler` uses it to build an instance declaration of `cls n`. -/
|
|
meta def instance_derive_handler (cls : name) (tac : tactic unit) (univ_poly := tt)
|
|
(modify_target : name → list expr → expr → tactic expr := λ _ _, pure) : derive_handler :=
|
|
λ p n,
|
|
if p.is_constant_of cls then
|
|
do decl ← get_decl n,
|
|
cls_decl ← get_decl cls,
|
|
env ← get_env,
|
|
guard (env.is_inductive n) <|> fail format!"failed to derive '{cls}', '{n}' is not an inductive type",
|
|
let ls := decl.univ_params.map $ λ n, if univ_poly then level.param n else level.zero,
|
|
-- incrementally build up target expression `Π (hp : p) [cls hp] ..., cls (n.{ls} hp ...)`
|
|
-- where `p ...` are the inductive parameter types of `n`
|
|
let tgt : expr := expr.const n ls,
|
|
⟨params, _⟩ ← mk_local_pis (decl.type.instantiate_univ_params (decl.univ_params.zip ls)),
|
|
let tgt := tgt.mk_app params,
|
|
tgt ← mk_app cls [tgt],
|
|
tgt ← modify_target n params tgt,
|
|
tgt ← params.enum.mfoldr (λ ⟨i, param⟩ tgt,
|
|
do -- add typeclass hypothesis for each inductive parameter
|
|
tgt ← do {
|
|
guard $ i < env.inductive_num_params n,
|
|
param_cls ← mk_app cls [param],
|
|
-- TODO(sullrich): omit some typeclass parameters based on usage of `param`?
|
|
pure $ expr.pi `a binder_info.inst_implicit param_cls tgt
|
|
} <|> pure tgt,
|
|
pure $ tgt.bind_pi param
|
|
) tgt,
|
|
(_, val) ← tactic.solve_aux tgt (intros >> tac),
|
|
val ← instantiate_mvars val,
|
|
let trusted := decl.is_trusted ∧ cls_decl.is_trusted,
|
|
add_decl (declaration.defn (n ++ cls)
|
|
(if univ_poly then decl.univ_params else [])
|
|
tgt val reducibility_hints.abbrev trusted),
|
|
set_basic_attribute `instance (n ++ cls) tt,
|
|
pure true
|
|
else pure false
|
|
|
|
@[derive_handler] meta def has_reflect_derive_handler :=
|
|
instance_derive_handler ``has_reflect mk_has_reflect_instance ff (λ n params tgt,
|
|
-- add additional `reflected` assumption for each parameter
|
|
params.mfoldr (λ param tgt,
|
|
do param_cls ← mk_app `reflected [param],
|
|
pure $ expr.pi `a binder_info.inst_implicit param_cls tgt
|
|
) tgt)
|
|
|
|
attribute [derive has_reflect] bool prod sum option interactive.loc pos
|