Merge branch 'enfore_not_allowing_big_maps' into 'dev'

Give an error when nesting a big_map inside another big_map

See merge request ligolang/ligo!518
This commit is contained in:
Sander 2020-03-26 10:39:18 +00:00
commit 91a6affdad
10 changed files with 177 additions and 19 deletions

View File

@ -8,9 +8,13 @@ hide_table_of_contents: true
import Syntax from '@theme/Syntax';
import SyntaxTitle from '@theme/SyntaxTitle';
A lazily deserialized map that's intended to store large amounts of data.
A lazily deserialized map that's intended to store large amounts of data.
Lazily means that storage is read or written per key on demand. Therefore
there are no `map`, `fold`, and `iter` operations as in
[Map](./map-reference).
The gast costs of deserialized maps are higher than standard maps as data is lazily deserialized.
The gast costs of big maps are higher than standard maps as data is lazily
deserialized.
<SyntaxTitle syntax="pascaligo">
type big_map ('key, 'value)
@ -47,15 +51,17 @@ type register = (address, move) big_map
<Syntax syntax="reasonligo">
The type of a big map from values of type `key` to
values of type `value` is `big_map (key, value)`.
values of type `value` is `big_map(key, value)`.
```reasonligo group=big_map
type move = (int, int);
type register = big_map (address, move);
type register = big_map(address, move);
```
</Syntax>
Be aware that a `big_map` cannot appear inside another `big_map`.
<SyntaxTitle syntax="pascaligo">
function empty : big_map ('key, 'value)
</SyntaxTitle>
@ -63,7 +69,7 @@ function empty : big_map ('key, 'value)
val empty : ('key, 'value) big_map
</SyntaxTitle>
<SyntaxTitle syntax="reasonligo">
let empty: big_map ('key, 'value)
let empty: big_map('key, 'value)
</SyntaxTitle>
Create an empty big_map.
@ -91,7 +97,7 @@ let empty : register = Big_map.empty
<Syntax syntax="reasonligo">
```reasonligo group=big_map
let empty : register = Big_map.empty
let empty: register = Big_map.empty
```
</Syntax>
@ -141,7 +147,7 @@ let moves : register =
<Syntax syntax="reasonligo">
```reasonligo group=big_map
let moves : register =
let moves: register =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
@ -156,7 +162,7 @@ function find_opt : 'key -> big_map ('key, 'value) -> option 'value
val find_opt : 'key -> ('key, 'value) big_map -> 'value option
</SyntaxTitle>
<SyntaxTitle syntax="reasonligo">
let find_opt : ('key, big_map ('key, 'value)) => option ('value)
let find_opt: ('key, big_map ('key, 'value)) => option ('value)
</SyntaxTitle>
Retrieve a value from a big map with the given key.
@ -191,8 +197,8 @@ let my_balance : move option =
<Syntax syntax="reasonligo">
```reasonligo group=big_map
let my_balance : option (move) =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, moves);
let my_balance: option (move) =
Big_map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
</Syntax>
@ -204,7 +210,7 @@ function update : 'key -> option 'value -> big_map ('key, 'value) -> big_map ('k
val update: 'key -> 'value option -> ('key, 'value) big_map -> ('key, 'value) big_map
</SyntaxTitle>
<SyntaxTitle syntax="reasonligo">
let update: ('key, option('value), big_map ('key, 'value)) => big_map ('key, 'value)
let update: ('key, option('value), big_map('key, 'value)) => big_map('key, 'value)
</SyntaxTitle>
Note: when `None` is used as a value, the value is removed from the big_map.
@ -255,9 +261,9 @@ let updated_map : register =
<Syntax syntax="reasonligo">
```reasonligo group=big_map
let updated_map : register =
let updated_map: register =
Big_map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves);
```
</Syntax>
@ -292,7 +298,7 @@ let add (m : register) : register =
```reasonligo group=big_map
let add = (m: register): register =>
Big_map.add
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (4,9), m);
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (4,9), m);
```
</Syntax>
@ -305,7 +311,7 @@ function remove: 'key -> big_map ('key, 'value) -> big_map ('key, 'value)
val remove: 'key -> ('key, 'value) big_map -> ('key, 'value) big_map
</SyntaxTitle>
<SyntaxTitle syntax="reasonligo">
let remove: ('key, big_map ('key, 'value)) => big_map ('key, 'value)
let remove: ('key, big_map('key, 'value)) => big_map('key, 'value)
</SyntaxTitle>
<Syntax syntax="pascaligo">
@ -340,8 +346,8 @@ let updated_map : register =
<Syntax syntax="reasonligo">
```reasonligo group=big_map
let updated_map : register =
Big_map.remove (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves)
let updated_map: register =
Big_map.remove(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves)
```
</Syntax>

View File

@ -1344,4 +1344,56 @@ let%expect_test _ =
* Visit our documentation: https://ligolang.org/docs/intro/what-and-why/
* Ask a question on our Discord: https://discord.gg/9rhYaEt
* Open a gitlab issue: https://gitlab.com/ligolang/ligo/issues/new
* Check the changelog by running 'ligo changelog' |}]
* Check the changelog by running 'ligo changelog' |}];
run_ligo_bad ["compile-contract"; bad_contract "nested_bigmap_1.religo"; "main"];
[%expect {|
ligo: It looks like you have nested a big map inside another big map. This is not supported. : {}
If you're not sure how to fix this error, you can
do one of the following:
* Visit our documentation: https://ligolang.org/docs/intro/what-and-why/
* Ask a question on our Discord: https://discord.gg/9rhYaEt
* Open a gitlab issue: https://gitlab.com/ligolang/ligo/issues/new
* Check the changelog by running 'ligo changelog' |}];
run_ligo_bad ["compile-contract"; bad_contract "nested_bigmap_2.religo"; "main"];
[%expect {|
ligo: It looks like you have nested a big map inside another big map. This is not supported. : {}
If you're not sure how to fix this error, you can
do one of the following:
* Visit our documentation: https://ligolang.org/docs/intro/what-and-why/
* Ask a question on our Discord: https://discord.gg/9rhYaEt
* Open a gitlab issue: https://gitlab.com/ligolang/ligo/issues/new
* Check the changelog by running 'ligo changelog' |}];
run_ligo_bad ["compile-contract"; bad_contract "nested_bigmap_3.religo"; "main"];
[%expect {|
ligo: It looks like you have nested a big map inside another big map. This is not supported. : {}
If you're not sure how to fix this error, you can
do one of the following:
* Visit our documentation: https://ligolang.org/docs/intro/what-and-why/
* Ask a question on our Discord: https://discord.gg/9rhYaEt
* Open a gitlab issue: https://gitlab.com/ligolang/ligo/issues/new
* Check the changelog by running 'ligo changelog' |}];
run_ligo_bad ["compile-contract"; bad_contract "nested_bigmap_4.religo"; "main"];
[%expect {|
ligo: It looks like you have nested a big map inside another big map. This is not supported. : {}
If you're not sure how to fix this error, you can
do one of the following:
* Visit our documentation: https://ligolang.org/docs/intro/what-and-why/
* Ask a question on our Discord: https://discord.gg/9rhYaEt
* Open a gitlab issue: https://gitlab.com/ligolang/ligo/issues/new
* Check the changelog by running 'ligo changelog' |}]

View File

@ -6,7 +6,7 @@ let all_expression_mapper = [
Literals.peephole_expression ;
]
let all_type_expression_mapper = [
Entrypoints_lenght_limit.peephole_type_expression ;
Entrypoints_length_limit.peephole_type_expression ;
]
let all_exp = List.map (fun el -> Helpers.Expression el) all_expression_mapper

View File

@ -0,0 +1,56 @@
open Ast_typed
open Trace
type contract_pass_data = Contract_passes.contract_pass_data
module Errors = struct
let no_nested_bigmap () =
let title = (thunk ("It looks like you have nested a big map inside another big map. This is not supported. ")) in
let message () = "" in
let data = [
(* ("location" , fun () -> Format.asprintf "%a" Location.pp loc) TODO once types have an actual location *)
] in
error ~data title message ()
end
let rec check_no_nested_bigmap is_in_bigmap e =
match e.type_content with
| T_operator (TC_big_map (_, _)) when is_in_bigmap ->
fail @@ Errors.no_nested_bigmap
| T_operator (TC_big_map (key, value)) ->
let%bind _ = check_no_nested_bigmap false key in
let%bind _ = check_no_nested_bigmap true value in
ok ()
| T_operator (TC_contract t)
| T_operator (TC_option t)
| T_operator (TC_list t)
| T_operator (TC_set t) ->
let%bind _ = check_no_nested_bigmap is_in_bigmap t in
ok ()
| T_operator (TC_map (a, b)) ->
let%bind _ = check_no_nested_bigmap is_in_bigmap a in
let%bind _ = check_no_nested_bigmap is_in_bigmap b in
ok ()
| T_operator (TC_arrow (a, b)) ->
let%bind _ = check_no_nested_bigmap false a in
let%bind _ = check_no_nested_bigmap false b in
ok ()
| T_sum s ->
let es = CMap.to_list s in
let%bind _ = bind_map_list (fun l -> check_no_nested_bigmap is_in_bigmap l) es in
ok ()
| T_record elm ->
let es = LMap.to_list elm in
let%bind _ = bind_map_list (fun l -> check_no_nested_bigmap is_in_bigmap l) es in
ok ()
| T_arrow { type1; type2 } ->
let%bind _ = check_no_nested_bigmap false type1 in
let%bind _ = check_no_nested_bigmap false type2 in
ok ()
| T_variable _
| T_constant _ ->
ok ()
let self_typing : contract_pass_data -> expression -> (bool * contract_pass_data * expression) result = fun dat el ->
let%bind _ = check_no_nested_bigmap false el.type_expression in
ok (true, dat, el)

View File

@ -6,6 +6,7 @@ let all_passes = [
let contract_passes = [
Contract_passes.self_typing ;
No_nested_big_map.self_typing ;
]
let all_program =

View File

@ -0,0 +1,10 @@
type bar = big_map (nat, int);
/* this should result in an error as nested big_maps are not supported: */
type storage = big_map (int, bar);
type return = (list (operation), storage);
let main = ((ignore, store): (unit, storage)): return => {
([]: list(operation), store)
};

View File

@ -0,0 +1,9 @@
/* this should result in an error as nested big_maps are not supported: */
type storage = big_map (nat, big_map (int, string));
type return = (list (operation), storage);
let main = ((ignore, store): (unit, storage)): return => {
([]: list(operation), store)
};

View File

@ -0,0 +1,15 @@
type bar = big_map (nat, int);
type foo = {
a: int,
b: bar
};
/* this should result in an error as nested big_maps are not supported: */
type storage = big_map(nat, foo);
type return = (list (operation), storage);
let main = ((ignore, store): (unit, storage)): return => {
([]: list(operation), store)
};

View File

@ -0,0 +1,9 @@
/* this should result in an error as nested big_maps are not supported: */
type storage = map (int, big_map (nat, big_map (int, string)));
type return = (list (operation), storage);
let main = ((ignore, store): (unit, storage)): return => {
([]: list(operation), store)
};