Commit graph

86 commits

Author SHA1 Message Date
Leonardo de Moura
b4c2861939 refactor(library/compiler): rename "erasure normal form" functions 2018-10-01 14:17:11 -07:00
Leonardo de Moura
81e9e95570 chore(library/compiler): erase_irrelevant ==> old_erase_irrelevant 2018-10-01 14:17:11 -07:00
Leonardo de Moura
5c2286f3c1 refactor(library/compiler): we preserve type information, but we do not preserve type correctness
The compiler applies transformations `t ==> s` where `t` and `s` are
only provably equal, but not definitionally equal. Moreover, in
dependent type theory `C[t]` may be type correct, but `C[s]` is not
when `t` is provably equal to `s`, but not definitionally equal.
Consider the following example:
```
fun n : nat,
  let v : nat      := 0+n in
  let b : bv (0+n) := bv.mk v in
  b
```
If we replace the first `0+n` with `n`, we produce the type incorrect
term
```
fun n : nat,
  let v : nat      := n in
  let b : bv (0+n) := bv.mk v in
  b
```
This is incorrect because `b : bv (0+n)` and `bv.mk v : bv n`, and
`0+n` is not definitionally equal to `n`.

We considered two approaches to address this problem:
1- A relaxed type checker (see deleted file `ctype_checker.cpp`).
This approach does not solve the problem, see example in the end
of the commit.

2- Introduce `lc_cast`-applications to "fix" type problems.  However,
it seems it is too expensive to detect all places that require a
`lc_ast` application. We did that in a few places, but there is major
omission: when we simplify `x : t := v` to `x : t := w` (like in the
example above), we did not find an efficient way to repair all
affected places. We have implemented the function `replace_fvar_with`,
but we would have to execute after each `x : t := v` ==> `x : t := w`
where `v` is not definitionally equal to `w`. We considered grouping
many `replace_fvar_with` together, but it would still be very
expensive. Basically, for any occurrence of `x` we would have to check
whether the resulting type changed or not. Another issue is that the
restrictions considered at `replace_fvar_with` seem to restrictive:
for example `x` cannot occur in lambda/let-decl types. This happens
very frequently in code that uses types such as `decidable p`.
Remark: note that the Lean3 simplifier does not have support for
simplyfing let-decls for this reason. It offers only two options:
expand the `let`, or skip it.

So, this commit gives up the idea of ensuring that each compiler step
produces a type correct Lean term. That is, we preserve type
information, but we do not guarantee the terms are type correct after
we apply compiler transformations.

Here are examples that demonstrate the `ctype_checker` approach does
not work.
```
def C : bool → Type → Type
| tt α := nat × α
| ff α := string × α

def ex  (α β : Type) (x : nat × α) (h₂ : α = β) : nat × β  :=
let f : Π (b : bool) (h₁ : b = tt) (α β : Type) (x : C b α) (h₂ : α = β), nat × β
      := λ (b : bool) (h₁ : b = tt) (α β : Type) (x : C b α) (h₂ : α = β),
         let x₁ : C b β := @eq.ndrec Type α  (λ z : Type, C b z) x β h₂ in
         @eq.ndrec bool b (λ z : bool, C z β) x₁ tt h₁
in f tt rfl α β x h₂
```
Now, suppose we want to put in LCNF. Then, we have to decide whether
each `eq.ndrec` will become a cast or not. Now, suppose we use the
compiler type checker `is_def_eq`.
Then, the first `eq.ndrec` application is `@eq.ndrec Type α  (λ z :
Type, C b z) x β h₂`, and we have that `x : C b α` and the expected
type is `C b β`, both types are stuck since they reduce to
`bool.cases_on b (string × α) (nat × α)` and  `bool.cases_on b (string
× β) (nat × β)` respectively. Thus, they are considered definitionally
equal, and we do not introduce a cast.

The second `eq.ndrec` application is
`@eq.ndrec bool b (λ z : bool, C z β) x₁ tt h₁`, and we have
`x₁ : C b β` and the expected type is `nat × β`, again they are definitionally equal since `C b β`.
Thus, in LCNF, the example above would be:
```
def ex  (α β : Type) (x : nat × α) (h₂ : α = β) : nat × β  :=
let f : Π (b : bool) (h₁ : b = tt) (α β : Type) (x : C b α) (h₂ : α = β), nat × β
      := λ (b : bool) (h₁ : b = tt) (α β : Type) (x : C b α) (h₂ : α = β), x
in f tt rfl α β x h₂
```

The compiler type checker (`ctype_checker`) would say this is a type correct term.
Now, suppose we reduce `f tt rfl α β x h₂` using `csimp`, this term
would reduce to  `x`.
Then, `f` is eliminated since it is not used anymore and we have the new simplified term
```
def ex  (α β : Type) (x : nat × α) (h₂ : α = β) : nat × β  := x
```
`ctype_checker` will report it to be type incorrect. Since, `x : nat × α`
and the result type is `nat × β`, and both are not stuck.
This example shows that by applying simple reduction rules (zeta/beta
in the example above) we can transform a type correct term into a type
incorrect one.

The type `any` is also problematic.  Consider the following example.
```
def ex (x : nat) : real :=
let f : any -> real := fun z, z in
f x
```
It is type correct. If we apply `csimp`, we will get.
```
def ex (x : nat) : real := x
```
which is type incorrect. Again, reduction may transform a type correct term into a type incorrect one.
Note that, I am not using anything fancy here. We are just treating
`any` as definitionally equal to any type.
2018-09-29 12:50:53 -07:00
Leonardo de Moura
1477036b36 fix(library/compiler/csimp): we may have partially applied cases_on applications in the computationally irrelevant part 2018-09-28 08:32:10 -07:00
Leonardo de Moura
2d8d0d5a6c feat(library/compiler): inline small functions and join points 2018-09-27 18:21:31 -07:00
Leonardo de Moura
d880b1c640 feat(library/compiler): add is_float_cases_on_worthwhile predicate and cleanup 2018-09-27 13:12:20 -07:00
Leonardo de Moura
21b8199bc4 feat(library/compiler/util): do not consider constructors to be cost zero 2018-09-26 08:48:06 -07:00
Leonardo de Moura
06e78b0e48 feat(library/compiler/csimp): create join points for float_cases_on 2018-09-25 19:34:29 -07:00
Leonardo de Moura
ee43d4a20a feat(library/compiler/util): add replace_fvar_with 2018-09-24 18:10:26 -07:00
Leonardo de Moura
07f96e8e09 feat(library/compiler): move let-decls that are used in only one minor to it 2018-09-23 19:27:06 -07:00
Leonardo de Moura
c75db3bfc6 feat(library/compiler): unfold [macro_definition] before LCNF/ANF conversion 2018-09-23 19:27:06 -07:00
Leonardo de Moura
ff2e28e557 feat(library/compiler): add cce: common case elimination 2018-09-20 21:38:57 -07:00
Leonardo de Moura
1534f17a89 feat(library/compiler/lcnf): add better support for complete-transition used in the equation compiler and x@ patterns 2018-09-20 21:38:57 -07:00
Leonardo de Moura
8a8f1a6821 fix(library/compiler/util): has_inline_attribute 2018-09-19 09:33:54 -07:00
Leonardo de Moura
d0e804b780 feat(library/compiler): add support for inlining to new compiler stack
We also delay the simplification of lambdas in the right hand side of let-declarations.
2018-09-18 17:24:25 -07:00
Leonardo de Moura
39d9a709d5 feat(library/compiler): improve simplification 2018-09-18 14:51:58 -07:00
Leonardo de Moura
ff725b8329 feat(library/compiler): simplify cheap beta reduction
The LCNF format contained may `let`-declarations of the form
```
x : (fun y, c) a := t
```
where `c` does not depend on `y`.
We reduce them to
```
x : c := t
```
2018-09-17 19:58:54 -07:00
Leonardo de Moura
33821f399c chore(library/compiler): lc_util.* ==> util.* 2018-09-17 08:50:50 -07:00
Leonardo de Moura
81067d355d chore(library/compiler): util.* ==> old_util.* 2018-09-17 08:44:45 -07:00
Leonardo de Moura
1cc60fdeac feat(library/compiler): add helper functions 2018-09-14 15:41:01 -07:00
Leonardo de Moura
5d00936a8f chore(*): remove some old_type_checker dependencies 2018-09-07 08:48:21 -07:00
Leonardo de Moura
58e91559d0 feat(*): use new inductive datatype module 2018-09-06 18:09:22 -07:00
Leonardo de Moura
22ba0a1155 chore(library): remove inverse.cpp
We used this module to implement inductive_compiler pack/unpack functions
2018-08-23 13:16:27 -07:00
Leonardo de Moura
82095cc018 refactor(kernel): split declaration into declaration and constant_info
This is just another step towards the design described at commit 16598391a07d4a
2018-08-22 17:53:11 -07:00
Leonardo de Moura
e9f843ddf6 refactor(kernel/expr): remove mlocal_* functions
The constructors `mvar` and `fvar` have different memory layouts.
2018-06-22 14:25:31 -07:00
Leonardo de Moura
13c532d0d4 fix(*): truncation bugs
- Lean strings (like std::string) may contain null characters. The
  codebase was ignoring this issue.

- We now have a wrapper `string_ref` for wrapping Lean string objects in
  C++. This wrapper also implements correctly the coercions std::string <-> string_ref.
  Remark: I also found a few places where the code relies on the
  following property which is not true
  Forall s : std::string, std::string(s.c_str()) == s

- `name` object wrapper was assuming that all numerals were small
  `nat` values. This is true in most cases, but the system would
  crash when processing if it is a big number.

- The commit tries to make sure runtime/util/kernel are correct.
  Modules that will be deleted contain many `TODO` comments
  indicating they may crash and/or produce incorrect results
  when strings contain null characters and numerals are big.

cc @kha

@kha: I thought about using `string` instead of `string_ref`.
We consistently use `std::string`. So, it should be fine, but I
was concerned about code readability.

After we bootstrap Lean4, we will be able to delete `lean::list`
template, and rename `lean::list_ref` to `lean::list`.

I am going to add `pair_ref` for wrapping Lean pair objects.
If we use `lean::string` instead of `lean::string_ref`, then
we should also use `lean::pair` instead of `lean::pair_ref`.
But, there is a problem in this case since we have
https://github.com/leanprover/lean4/blob/master/src/util/pair.h#L13
:(
2018-06-15 16:05:11 -07:00
Leonardo de Moura
c0e1d05199 chore(kernel): type_checker ==> old_type_checker 2018-06-06 16:10:40 -07:00
Leonardo de Moura
bdea7d420d chore(*): type_context ==> type_context_old 2018-03-05 12:38:24 -08:00
Leonardo de Moura
73eda00ba3 refactor(library/compiler): mk_unused_name ==> mk_compiler_unused_name 2018-02-21 15:04:19 -08:00
Leonardo de Moura
6ba4607c28 refactor(library/compiler): rename compiler mk_fresh_name to mk_unused_name 2018-02-21 15:04:19 -08:00
Leonardo de Moura
dbeafaaeed chore(library/compiler/util): remove dead code 2018-02-02 08:34:14 -08:00
Leonardo de Moura
22988bb95d feat(library/compiler): avoid pack/unpack overhead produced by the inductive_compiler in the code generator
TODO: make sure the user is not manually using cases_on for the
auxiliary datatype generated by the inductive_compiler to
destruct nested inductives.
2017-03-04 13:54:44 -08:00
Leonardo de Moura
932d14241b chore(kernel): remove support for mutually inductive datatypes from the kernel 2016-09-10 17:39:17 -07:00
Leonardo de Moura
399b83122c refactor(library): move vm to a separate directory 2016-05-12 14:45:06 -07:00
Leonardo de Moura
1820bdc430 feat(library/compiler): generate better auxiliary function names 2016-05-11 10:26:51 -07:00
Leonardo de Moura
de9df69ef6 refactor(src): move compiler folder to library 2016-05-09 13:28:00 -07:00
Renamed from src/compiler/util.cpp (Browse further)