From 4f9d4e5c073cbb644645e022576f5100c36adf0d Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Thu, 20 Jun 2019 12:11:43 +0200 Subject: [PATCH 1/4] Update compiler for bytes --- src/aeso_ast_to_fcode.erl | 17 +++++------------ src/aeso_fcode_to_fate.erl | 6 ++---- src/aeso_vm_decode.erl | 4 +--- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 26b4c1d..7c760a4 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -37,8 +37,7 @@ -type flit() :: {int, integer()} | {string, binary()} - | {hash, binary()} - | {signature, binary()} + | {bytes, binary()} | {account_pubkey, binary()} | {contract_pubkey, binary()} | {oracle_pubkey, binary()} @@ -90,8 +89,7 @@ | {map, ftype(), ftype()} | {tuple, [ftype()]} | address - | hash - | signature + | {bytes, non_neg_integer()} | contract | {oracle, ftype(), ftype()} %% Query type, Response type | oracle_query @@ -320,10 +318,8 @@ type_to_fcode(Env, Sub, {tuple_t, _, Types}) -> type_to_fcode(Env, Sub, {record_t, Fields}) -> FieldType = fun({field_t, _, _, Ty}) -> Ty end, type_to_fcode(Env, Sub, {tuple_t, [], lists:map(FieldType, Fields)}); -type_to_fcode(_Env, _Sub, {bytes_t, _, 32}) -> hash; -type_to_fcode(_Env, _Sub, {bytes_t, _, 64}) -> signature; -type_to_fcode(_Env, _Sub, {bytes_t, _, _N}) -> - string; %% TODO: add bytes type to FATE +type_to_fcode(_Env, _Sub, {bytes_t, _, N}) -> + {bytes, N}; type_to_fcode(_Env, Sub, {tvar, _, X}) -> maps:get(X, Sub, {tvar, X}); type_to_fcode(Env, Sub, {fun_t, _, Named, Args, Res}) -> @@ -367,10 +363,7 @@ expr_to_fcode(_Env, _Type, {account_pubkey, _, K}) -> {lit, {account_pubkey, K} expr_to_fcode(_Env, _Type, {contract_pubkey, _, K}) -> {lit, {contract_pubkey, K}}; expr_to_fcode(_Env, _Type, {oracle_pubkey, _, K}) -> {lit, {oracle_pubkey, K}}; expr_to_fcode(_Env, _Type, {oracle_query_id, _, K}) -> {lit, {oracle_query_id, K}}; - -expr_to_fcode(_Env, _Type, {bytes, _, Bin = <<_:32/binary>>}) -> {lit, {hash, Bin}}; -expr_to_fcode(_Env, _Type, {bytes, _, Bin = <<_:64/binary>>}) -> {lit, {signature, Bin}}; -expr_to_fcode(_Env, _Type, {bytes, _, Bin}) -> {lit, {string, Bin}}; +expr_to_fcode(_Env, _Type, {bytes, _, B}) -> {lit, {bytes, B}}; %% Variables expr_to_fcode(Env, _Type, {id, _, X}) -> resolve_var(Env, [X]); diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 5441ae3..679481c 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -161,8 +161,7 @@ type_to_scode(integer) -> integer; type_to_scode(boolean) -> boolean; type_to_scode(string) -> string; type_to_scode(address) -> address; -type_to_scode(hash) -> hash; -type_to_scode(signature) -> signature; +type_to_scode({bytes, N}) -> {bytes, N}; type_to_scode(contract) -> contract; type_to_scode({oracle, _, _}) -> oracle; type_to_scode(oracle_query) -> oracle_query; @@ -236,8 +235,7 @@ lit_to_fate(L) -> case L of {int, N} -> aeb_fate_data:make_integer(N); {string, S} -> aeb_fate_data:make_string(S); - {hash, H} -> aeb_fate_data:make_hash(H); - {signature, S} -> aeb_fate_data:make_signature(S); + {bytes, B} -> aeb_fate_data:make_bytes(B); {bool, B} -> aeb_fate_data:make_boolean(B); {account_pubkey, K} -> aeb_fate_data:make_address(K); {contract_pubkey, K} -> aeb_fate_data:make_contract(K); diff --git a/src/aeso_vm_decode.erl b/src/aeso_vm_decode.erl index edc79f1..bf61a48 100644 --- a/src/aeso_vm_decode.erl +++ b/src/aeso_vm_decode.erl @@ -69,9 +69,7 @@ from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin}; from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin}; from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin}; from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin}; -from_fate({bytes_t, _, 32}, ?FATE_HASH(Bin)) -> {bytes, [], Bin}; -from_fate({bytes_t, _, 64}, ?FATE_SIGNATURE(Bin)) -> {bytes, [], Bin}; -from_fate({bytes_t, _, N}, Bin) when size(Bin) == N -> {bytes, [], Bin}; +from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin}; from_fate({id, _, "bits"}, ?FATE_BITS(Bin)) -> error({todo, bits, Bin}); from_fate({id, _, "int"}, N) when is_integer(N) -> {int, [], N}; from_fate({id, _, "bool"}, B) when is_boolean(B) -> {bool, [], B}; From 592869bf75bb5285ac0ae298f64a70a782459aed Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Thu, 20 Jun 2019 14:36:15 +0200 Subject: [PATCH 2/4] aebytecode commit --- rebar.config | 2 +- rebar.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rebar.config b/rebar.config index 569502c..77b30e8 100644 --- a/rebar.config +++ b/rebar.config @@ -2,7 +2,7 @@ {erl_opts, [debug_info]}. -{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"f91c8fa"}}} +{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"59af12b"}}} , {getopt, "1.0.1"} , {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}} diff --git a/rebar.lock b/rebar.lock index 0cddda9..c27ddea 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,7 +1,7 @@ {"1.1.0", [{<<"aebytecode">>, {git,"https://github.com/aeternity/aebytecode.git", - {ref,"f91c8fabdd01cf911fb194862a50f9635c96c0e5"}}, + {ref,"59af12bf349edafcd470cd3ccefff09cacd2d010"}}, 0}, {<<"aeserialization">>, {git,"https://github.com/aeternity/aeserialization.git", From d38367e0234f2a60d72df32e5963d5fb7a7a5f61 Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Thu, 20 Jun 2019 16:01:46 +0200 Subject: [PATCH 3/4] Fix bug in type checker --- src/aeso_ast_infer_types.erl | 4 ++++ test/aeso_compiler_tests.erl | 3 ++- test/contracts/namespace_bug.aes | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 test/contracts/namespace_bug.aes diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index a3455eb..87dd677 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -1814,6 +1814,10 @@ occurs_check1(R, {tuple_t, _, Ts}) -> occurs_check(R, Ts); occurs_check1(R, {named_arg_t, _, _, T, _}) -> occurs_check(R, T); +occurs_check1(R, {record_t, Fields}) -> + occurs_check(R, Fields); +occurs_check1(R, {field_t, _, _, T}) -> + occurs_check(R, T); occurs_check1(R, [H | T]) -> occurs_check(R, H) orelse occurs_check(R, T); occurs_check1(_, []) -> false. diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index b37ddc4..a894cac 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -114,7 +114,8 @@ compilable_contracts() -> "bitcoin_auth", "address_literals", "bytes_equality", - "address_chain" + "address_chain", + "namespace_bug" ]. not_yet_compilable(fate) -> diff --git a/test/contracts/namespace_bug.aes b/test/contracts/namespace_bug.aes new file mode 100644 index 0000000..62ad202 --- /dev/null +++ b/test/contracts/namespace_bug.aes @@ -0,0 +1,12 @@ + +namespace Foo = + + record bla = {x : int, y : bool} + + function bar() : Foo.bla = {x = 17, y = true} + +contract Bug = + + // Crashed the type checker + function foo () = Foo.bar() + From 7fa98892a8307debfd830ae8cd301f10516cb4d6 Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Fri, 21 Jun 2019 14:16:26 +0200 Subject: [PATCH 4/4] Fix compiler crash on missing let body --- src/aeso_ast_infer_types.erl | 17 ++++++++++++++--- test/aeso_compiler_tests.erl | 6 +++++- test/contracts/type_errors.aes | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 87dd677..cd8d829 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -1134,7 +1134,13 @@ infer_expr(Env, {lam, Attrs, Args, Body}) -> {'case', _, {typed, _, {tuple, _, NewArgPatterns}, _}, NewBody} = infer_case(Env, Attrs, {tuple, Attrs, ArgPatterns}, {tuple_t, Attrs, ArgTypes}, Body, ResultType), NewArgs = [{arg, As, NewPat, NewT} || {typed, As, NewPat, NewT} <- NewArgPatterns], - {typed, Attrs, {lam, Attrs, NewArgs, NewBody}, {fun_t, Attrs, [], ArgTypes, ResultType}}. + {typed, Attrs, {lam, Attrs, NewArgs, NewBody}, {fun_t, Attrs, [], ArgTypes, ResultType}}; +infer_expr(Env, Let = {letval, Attrs, _, _, _}) -> + type_error({missing_body_for_let, Attrs}), + infer_expr(Env, {block, Attrs, [Let, abort_expr(Attrs, "missing body")]}); +infer_expr(Env, Let = {letfun, Attrs, _, _, _, _}) -> + type_error({missing_body_for_let, Attrs}), + infer_expr(Env, {block, Attrs, [Let, abort_expr(Attrs, "missing body")]}). infer_named_arg(Env, NamedArgs, {named_arg, Ann, Id, E}) -> CheckedExpr = {typed, _, _, ArgType} = infer_expr(Env, E), @@ -1208,6 +1214,8 @@ infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) -> %% NewStmts = infer_block(Env, Attrs, Stmts, BlockType) infer_block(_Env, Attrs, [], BlockType) -> error({impossible, empty_block, Attrs, BlockType}); +infer_block(Env, _, [E], BlockType) -> + [check_expr(Env, E, BlockType)]; infer_block(Env, Attrs, [Def={letfun, Ann, _, _, _, _}|Rest], BlockType) -> {{Name, TypeSig}, LetFun} = infer_letfun(Env, Def), FunT = freshen_type(typesig_to_fun_t(TypeSig)), @@ -1218,8 +1226,6 @@ infer_block(Env, _, [{letval, Attrs, Pattern, Type, E}|Rest], BlockType) -> {'case', _, NewPattern, {typed, _, {block, _, NewRest}, _}} = infer_case(Env, Attrs, Pattern, PatType, {block, Attrs, Rest}, BlockType), [{letval, Attrs, NewPattern, Type, NewE}|NewRest]; -infer_block(Env, _, [E], BlockType) -> - [check_expr(Env, E, BlockType)]; infer_block(Env, Attrs, [E|Rest], BlockType) -> [infer_expr(Env, E)|infer_block(Env, Attrs, Rest, BlockType)]. @@ -1255,6 +1261,9 @@ infer_prefix({IntOp,As}) when IntOp =:= '-' -> Int = {id, As, "int"}, {fun_t, As, [], [Int], Int}. +abort_expr(Ann, Str) -> + {app, Ann, {id, Ann, "abort"}, [{string, Ann, Str}]}. + free_vars({int, _, _}) -> []; free_vars({char, _, _}) -> @@ -2029,6 +2038,8 @@ pp_error({init_depends_on_state, Which, [_Init | Chain]}) -> [if Which == put -> "write"; true -> "read" end, [ io_lib:format(" - ~s (at ~s)~s\n", [Fun, pp_loc(Ann), WhichCalls(Fun)]) || {[_, Fun], Ann} <- Chain]]); +pp_error({missing_body_for_let, Ann}) -> + io_lib:format("Let binding at ~s must be followed by an expression\n", [pp_loc(Ann)]); pp_error(Err) -> io_lib:format("Unknown error: ~p\n", [Err]). diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index a894cac..8d95522 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -208,7 +208,11 @@ failing_contracts() -> <<"Repeated argument y to function repeated_arg (at line 44, column 12).">>, <<"No record type with fields y, z (at line 14, column 22)">>, <<"The field z is missing when constructing an element of type r2 (at line 15, column 24)">>, - <<"Record type r2 does not have field y (at line 15, column 22)">>]} + <<"Record type r2 does not have field y (at line 15, column 22)">>, + <<"Let binding at line 47, column 5 must be followed by an expression">>, + <<"Let binding at line 50, column 5 must be followed by an expression">>, + <<"Let binding at line 54, column 5 must be followed by an expression">>, + <<"Let binding at line 58, column 5 must be followed by an expression">>]} , {"init_type_error", [<<"Cannot unify string\n" " and map(int, int)\n" diff --git a/test/contracts/type_errors.aes b/test/contracts/type_errors.aes index ef4718e..4c3f879 100644 --- a/test/contracts/type_errors.aes +++ b/test/contracts/type_errors.aes @@ -42,3 +42,18 @@ contract Test = set_x(set_x(x, r), x) function repeated_arg(x : int, y, x : string, y : bool) : string = x + + function missing1() = + let x = 0 + + function missing_fun1() = + let f(x) = x + + function missing2() = + let x = 0 + let y = 0 + + function missing_fun2() = + let f() = 0 + let g() = f() +