.
This commit is contained in:
parent
9de13098aa
commit
0ca23009b4
@ -1181,16 +1181,16 @@ check_type(Env, T = {dep_variant_t, Ann, TId, Base, undefined, Constrs}, Arity)
|
|||||||
|| {constr_t, CAnn, Con, CArgs} <- Constrs
|
|| {constr_t, CAnn, Con, CArgs} <- Constrs
|
||||||
],
|
],
|
||||||
Constrs1 =
|
Constrs1 =
|
||||||
[ case [ ConstrNew
|
[ case [ ConstrNew || ConstrNew = {constr_t, _, CNameNew, _} <- Constrs,
|
||||||
|| ConstrNew = {constr_t, _, CNameNew, _} <- Constrs,
|
name(CNameNew) == name(CNameOld)] of
|
||||||
name(CNameNew) == name(CNameOld)] of
|
|
||||||
[{constr_t, FAnn, CName, CArgs}] ->
|
[{constr_t, FAnn, CName, CArgs}] ->
|
||||||
{constr_t, FAnn, CName,
|
{constr_t, FAnn, CName,
|
||||||
[ check_type(Env, CArg) || CArg <- CArgs ]
|
[ check_type(Env, CArg) || CArg <- CArgs ]
|
||||||
};
|
};
|
||||||
_ -> ConstrOld
|
_ -> {constr_t, CAnnOld, CNameOld,
|
||||||
|
[{empty_sub, CAnnOld, CArgOld} || CArgOld <- CArgsOld]}
|
||||||
end
|
end
|
||||||
|| ConstrOld = {constr_t, _, CNameOld, _} <- TrueConstrs
|
|| {constr_t, CAnnOld, CNameOld, CArgsOld} <- TrueConstrs
|
||||||
],
|
],
|
||||||
OnQcon = fun(A) -> qcon(aeso_syntax:get_ann(QId), lists:droplast(qname(QId)) ++ qname(A)) end,
|
OnQcon = fun(A) -> qcon(aeso_syntax:get_ann(QId), lists:droplast(qname(QId)) ++ qname(A)) end,
|
||||||
TagPred =
|
TagPred =
|
||||||
@ -2685,6 +2685,8 @@ occurs_check1(R, [H | T]) ->
|
|||||||
occurs_check(R, H) orelse occurs_check(R, T);
|
occurs_check(R, H) orelse occurs_check(R, T);
|
||||||
occurs_check1(R, {named_t, _, _, T}) ->
|
occurs_check1(R, {named_t, _, _, T}) ->
|
||||||
occurs_check1(R, T);
|
occurs_check1(R, T);
|
||||||
|
occurs_check1(R, {empty_sub, _, T}) ->
|
||||||
|
occurs_check1(R, T);
|
||||||
occurs_check1(R, {refined_t, _, _, T, _}) ->
|
occurs_check1(R, {refined_t, _, _, T, _}) ->
|
||||||
occurs_check1(R, T);
|
occurs_check1(R, T);
|
||||||
occurs_check1(R, {dep_record_t, _, _, T}) ->
|
occurs_check1(R, {dep_record_t, _, _, T}) ->
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
, namespaces = #{} :: #{qname() => namespace_type()}
|
, namespaces = #{} :: #{qname() => namespace_type()}
|
||||||
, stateful = #{} :: #{qname() => boolean()}
|
, stateful = #{} :: #{qname() => boolean()}
|
||||||
, tc_env
|
, tc_env
|
||||||
|
, falsified = false :: boolean()
|
||||||
}).
|
}).
|
||||||
-type env() :: #env{}.
|
-type env() :: #env{}.
|
||||||
|
|
||||||
@ -771,6 +772,11 @@ fresh_liquid(Env, Hint, Type) ->
|
|||||||
fresh_liquid(Env, covariant, Hint, Type).
|
fresh_liquid(Env, covariant, Hint, Type).
|
||||||
|
|
||||||
-spec fresh_liquid(env(), variance(), name(), term()) -> term().
|
-spec fresh_liquid(env(), variance(), name(), term()) -> term().
|
||||||
|
%fresh_liquid(Env, Variance, Hint, {empty_sub, _, T}) ->
|
||||||
|
% Liq = fresh_liquid(Env, Variance, Hint, T),
|
||||||
|
% Empty = empty_type(Variance, Liq),
|
||||||
|
% ?DBG("EMPTY: ~s -> ~s", [aeso_pretty:pp(type, Liq), aeso_pretty:pp(type, Empty)]),
|
||||||
|
% Empty;
|
||||||
fresh_liquid(_Env, _Variance, _Hint, Type = {refined_t, _, _, _, _}) ->
|
fresh_liquid(_Env, _Variance, _Hint, Type = {refined_t, _, _, _, _}) ->
|
||||||
Type;
|
Type;
|
||||||
fresh_liquid(_Env, _Variance, _Hint, Type = {dep_fun_t, _, _, _}) ->
|
fresh_liquid(_Env, _Variance, _Hint, Type = {dep_fun_t, _, _, _}) ->
|
||||||
@ -905,7 +911,7 @@ fresh_liquid_arg(Env, Variance, Id, Type) ->
|
|||||||
{{refined_t, Ann, Id, Base, apply_subst(TId, Id, Pred)}, [{TId, Id}]};
|
{{refined_t, Ann, Id, Base, apply_subst(TId, Id, Pred)}, [{TId, Id}]};
|
||||||
{dep_list_t, Ann, TId, Elem, Pred} ->
|
{dep_list_t, Ann, TId, Elem, Pred} ->
|
||||||
{{dep_list_t, Ann, Id, Elem, apply_subst(TId, Id, Pred)}, [{TId, Id}]};
|
{{dep_list_t, Ann, Id, Elem, apply_subst(TId, Id, Pred)}, [{TId, Id}]};
|
||||||
{dep_variant_t, Ann, TId, Tag, Constrs} ->
|
{dep_variant_t, Ann, TId, Tag, Constrs} -> %% FIXME: TYPE?
|
||||||
{{dep_variant_t, Ann, Id, apply_subst(TId, Id, Tag), Constrs}, [{TId, Id}]};
|
{{dep_variant_t, Ann, Id, apply_subst(TId, Id, Tag), Constrs}, [{TId, Id}]};
|
||||||
T -> {T, []}
|
T -> {T, []}
|
||||||
end,
|
end,
|
||||||
@ -953,6 +959,44 @@ fresh_wildcards([H|T]) ->
|
|||||||
[fresh_wildcards(H)|fresh_wildcards(T)];
|
[fresh_wildcards(H)|fresh_wildcards(T)];
|
||||||
fresh_wildcards(X) -> X.
|
fresh_wildcards(X) -> X.
|
||||||
|
|
||||||
|
empty_type(covariant, {refined_t, Ann, Self, Base, _}) ->
|
||||||
|
{refined_t, Ann, Self, Base, [{bool, Ann, false}]};
|
||||||
|
empty_type(contravariant, {refined_t, Ann, Self, Base, _}) ->
|
||||||
|
{refined_t, Ann, Self, Base, []};
|
||||||
|
empty_type(covariant, {dep_list_t, Ann, Self, Elem, _}) ->
|
||||||
|
{dep_list_t, Ann, Self, empty_type(covariant, Elem), [{bool, Ann, false}]};
|
||||||
|
empty_type(contravariant, {dep_list_t, Ann, Self, Elem, _}) ->
|
||||||
|
{dep_list_t, Ann, Self, empty_type(contravariant, Elem), []};
|
||||||
|
empty_type(Variance, {dep_fun_t, Ann, Args, Ret}) ->
|
||||||
|
{dep_fun_t, Ann,
|
||||||
|
[{dep_arg_t, AAnn, Name, empty_type(switch_variance(Variance), ArgT)}
|
||||||
|
|| {dep_arg_t, AAnn, Name, ArgT} <- Args],
|
||||||
|
empty_type(Variance, Ret)
|
||||||
|
};
|
||||||
|
empty_type(Variance, {dep_record_t, Ann, Base, Fields}) ->
|
||||||
|
{dep_record_t, Ann, Base,
|
||||||
|
[ {field, FAnn, Name, empty_type(Variance, Type)}
|
||||||
|
|| {field, FAnn, Name, Type} <- Fields
|
||||||
|
]
|
||||||
|
};
|
||||||
|
empty_type(Variance, {dep_variant_t, Ann, Id, Base, Tag, Constrs}) ->
|
||||||
|
Tag1 = case Variance of
|
||||||
|
covariant ->
|
||||||
|
[{bool, Ann, false}];
|
||||||
|
contravariant ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
{dep_variant_t, Ann, Id, Base, Tag1,
|
||||||
|
[ {constr_t, CAnn, CName,
|
||||||
|
[empty_type(Variance, CArg) || CArg <- CArgs]
|
||||||
|
}
|
||||||
|
|| {constr_t, CAnn, CName, CArgs} <- Constrs
|
||||||
|
]
|
||||||
|
};
|
||||||
|
empty_type(Variance, {tuple, Ann, Ts}) ->
|
||||||
|
{tuple, Ann, [empty_type(Variance, T) || T <- Ts]}.
|
||||||
|
%empty_type(_, T) -> T.
|
||||||
|
|
||||||
|
|
||||||
%% -- Utils --------------------------------------------------------------------
|
%% -- Utils --------------------------------------------------------------------
|
||||||
|
|
||||||
@ -986,6 +1030,7 @@ add_error(Err) ->
|
|||||||
%% -- Entrypoint ---------------------------------------------------------------
|
%% -- Entrypoint ---------------------------------------------------------------
|
||||||
|
|
||||||
refine_ast(TCEnv, AST) ->
|
refine_ast(TCEnv, AST) ->
|
||||||
|
?DBG("INITIALISING REFINER"),
|
||||||
Env0 = init_env(TCEnv),
|
Env0 = init_env(TCEnv),
|
||||||
Env1 = with_cool_ints_from(TCEnv, with_cool_ints_from(AST, Env0)),
|
Env1 = with_cool_ints_from(TCEnv, with_cool_ints_from(AST, Env0)),
|
||||||
Env2 = register_namespaces(AST, Env1),
|
Env2 = register_namespaces(AST, Env1),
|
||||||
@ -993,15 +1038,24 @@ refine_ast(TCEnv, AST) ->
|
|||||||
Env4 = register_stateful(AST, Env3),
|
Env4 = register_stateful(AST, Env3),
|
||||||
try
|
try
|
||||||
Env5 = register_ast_funs(AST, Env4),
|
Env5 = register_ast_funs(AST, Env4),
|
||||||
|
?DBG("GENERATING CONSTRAINTS"),
|
||||||
{AST1, CS0} = constr_ast(Env5, AST),
|
{AST1, CS0} = constr_ast(Env5, AST),
|
||||||
|
?DBG("DONE:\n~s", [string:join([aeso_pretty:pp(constr, C) || C <- CS0], "\n\n")]),
|
||||||
|
?DBG("SPLITTING ~p CONSTRAINTS", [length(CS0)]),
|
||||||
CS1 = split_constr(CS0),
|
CS1 = split_constr(CS0),
|
||||||
%[ ?DBG("SUBTYPE ~p:\n~s\n<:\n~s", [Id, aeso_pretty:pp(type, strip_typed(T1)), aeso_pretty:pp(type, strip_typed(T2))])
|
?DBG("DONE:\n~s", [string:join([aeso_pretty:pp(constr, C) || C <- CS1], "\n\n")]),
|
||||||
% || {subtype, Id, _, _, T1, T2} <- CS1
|
[ ?DBG("SUBTYPE ~p:\n~s\n<:\n~s\n", [Id, aeso_pretty:pp(type, strip_typed(T1)), aeso_pretty:pp(type, strip_typed(T2))])
|
||||||
%],
|
|| {subtype, Id, _, _, T1, T2} <- CS1
|
||||||
|
],
|
||||||
|
?DBG("SOLVING ~p CONSTRAINTS", [length(CS1)]),
|
||||||
{Env5, solve(Env5, AST1, CS1)}
|
{Env5, solve(Env5, AST1, CS1)}
|
||||||
of
|
of
|
||||||
{EnvErlangSucks, {ok, AST2}} -> {ok, {EnvErlangSucks, AST2}};
|
{EnvErlangSucks, {ok, AST2}} ->
|
||||||
{_, Err = {error, _}} -> Err
|
?DBG("REFINEMENT FINISHED"),
|
||||||
|
?DBG("LIQUID ACI:\n~s", [aeso_pretty:pp(decls, AST2)]),
|
||||||
|
{ok, {EnvErlangSucks, AST2}};
|
||||||
|
{_, Err = {error, _}} ->
|
||||||
|
Err
|
||||||
catch {ErrType, _}=E
|
catch {ErrType, _}=E
|
||||||
when ErrType =:= refinement_errors;
|
when ErrType =:= refinement_errors;
|
||||||
ErrType =:= overwrite;
|
ErrType =:= overwrite;
|
||||||
@ -1075,8 +1129,11 @@ constr_letfun(Env0, {letfun, Ann, Id, Args, RetT, Body}, S0) ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
Body3 = a_normalize(Body2),
|
Body3 = a_normalize(Body2),
|
||||||
%?DBG("ANORM\n~s", [aeso_pretty:pp(expr, Body1)]),
|
% ?DBG("FUN\n~s", [aeso_pretty:pp(expr, Body0)]),
|
||||||
%?DBG("PURIFIED\n~s", [aeso_pretty:pp(expr, Body3)]),
|
?DBG("FUN\n~p", [Body0]),
|
||||||
|
?DBG("ANORM\n~s", [aeso_pretty:pp(expr, Body1)]),
|
||||||
|
?DBG("PURIFIED\n~p", [Body3]),
|
||||||
|
% ?DBG("PURIFIED\n~s", [aeso_pretty:pp(expr, Body3)]),
|
||||||
{BodyT, S1} = constr_expr(Env3, Body3, S0),
|
{BodyT, S1} = constr_expr(Env3, Body3, S0),
|
||||||
InnerFunT = {dep_fun_t, Ann, ArgsT, BodyT},
|
InnerFunT = {dep_fun_t, Ann, ArgsT, BodyT},
|
||||||
S3 = [ {subtype, constr_id(letfun_top_decl), Ann, Env3, BodyT, GlobRetT}
|
S3 = [ {subtype, constr_id(letfun_top_decl), Ann, Env3, BodyT, GlobRetT}
|
||||||
@ -1218,7 +1275,7 @@ constr_expr(_Env, I = {int, Ann, _}, T = ?int_tp, S) ->
|
|||||||
{?refined(T, [?op(Ann, ?nu(Ann), '==', I)]), S};
|
{?refined(T, [?op(Ann, ?nu(Ann), '==', I)]), S};
|
||||||
constr_expr(_Env, I = {char, Ann, _}, T, S) ->
|
constr_expr(_Env, I = {char, Ann, _}, T, S) ->
|
||||||
{?refined(T, [?op(Ann, ?nu(Ann), '==', I)]), S};
|
{?refined(T, [?op(Ann, ?nu(Ann), '==', I)]), S};
|
||||||
constr_expr(_Env, {address, _, _}, T, S0) ->
|
constr_expr(_Env, {account_pubkey, _, _}, T, S0) ->
|
||||||
{?refined(T), S0};
|
{?refined(T), S0};
|
||||||
constr_expr(_Env, {string, _, _}, T, S0) ->
|
constr_expr(_Env, {string, _, _}, T, S0) ->
|
||||||
{?refined(T), S0};
|
{?refined(T), S0};
|
||||||
@ -1340,8 +1397,8 @@ constr_expr(Env, {app, Ann, ?typed_p({'++', OpAnn}), [OpL, OpR]}, {app_t, _, {id
|
|||||||
constr_expr(Env, {app, Ann, ?typed_p({id, _, "abort"}), _}, T, S0) ->
|
constr_expr(Env, {app, Ann, ?typed_p({id, _, "abort"}), _}, T, S0) ->
|
||||||
ExprT = fresh_liquid(Env, "abort", T),
|
ExprT = fresh_liquid(Env, "abort", T),
|
||||||
{ExprT,
|
{ExprT,
|
||||||
[ {unreachable, constr_id(abort), Ann, Env}
|
[ {well_formed, constr_id(abort), Env, ExprT}
|
||||||
, {well_formed, constr_id(abort), Env, ExprT}
|
% , {unreachable, constr_id(abort), Ann, Env}
|
||||||
|S0
|
|S0
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@ -1940,7 +1997,8 @@ split_constr([H|T], Acc) ->
|
|||||||
HC = split_constr1(H),
|
HC = split_constr1(H),
|
||||||
split_constr(T, HC ++ Acc);
|
split_constr(T, HC ++ Acc);
|
||||||
split_constr([], Acc) ->
|
split_constr([], Acc) ->
|
||||||
filter_obvious(Acc).
|
Acc.
|
||||||
|
% filter_obvious(Acc).
|
||||||
|
|
||||||
split_constr1(C = {subtype, Ref, Ann, Env0, SubT, SupT}) ->
|
split_constr1(C = {subtype, Ref, Ann, Env0, SubT, SupT}) ->
|
||||||
case {SubT, SupT} of
|
case {SubT, SupT} of
|
||||||
@ -2011,9 +2069,19 @@ split_constr1(C = {subtype, Ref, Ann, Env0, SubT, SupT}) ->
|
|||||||
?refined(IdSub, BaseSub, LenQualSub),
|
?refined(IdSub, BaseSub, LenQualSub),
|
||||||
?refined(IdSup, ?int_t(?ann_of(DepElemSup)), LenQualSup)}
|
?refined(IdSup, ?int_t(?ann_of(DepElemSup)), LenQualSup)}
|
||||||
);
|
);
|
||||||
|
{ {empty_sub, _, _}
|
||||||
|
, _
|
||||||
|
} ->
|
||||||
|
[];
|
||||||
|
{ _
|
||||||
|
, {empty_sub, _, T}
|
||||||
|
} ->
|
||||||
|
split_constr1({subtype, Ref, Ann, Env0, SubT, empty_type(covariant, T)});
|
||||||
_ ->
|
_ ->
|
||||||
[C]
|
[C]
|
||||||
end;
|
end;
|
||||||
|
% ?DBG("SPLIT ~s\nINTO (LEN ~p)\n~s\n\n-----", [aeso_pretty:pp(constr, C), length(R), string:join([aeso_pretty:pp(constr, ASD) || ASD <- R], "\n")]),
|
||||||
|
% R;
|
||||||
split_constr1(C = {well_formed, Ref, Env0, T}) ->
|
split_constr1(C = {well_formed, Ref, Env0, T}) ->
|
||||||
case T of
|
case T of
|
||||||
{dep_fun_t, _, Args, Ret} ->
|
{dep_fun_t, _, Args, Ret} ->
|
||||||
@ -2043,6 +2111,8 @@ split_constr1(C = {well_formed, Ref, Env0, T}) ->
|
|||||||
[ {well_formed, Ref, Env0, ?refined(Id, ?int_t(Ann), LenQual)}
|
[ {well_formed, Ref, Env0, ?refined(Id, ?int_t(Ann), LenQual)}
|
||||||
, {well_formed, Ref, Env0, DepElem}
|
, {well_formed, Ref, Env0, DepElem}
|
||||||
]);
|
]);
|
||||||
|
{empty_sub, _, T} ->
|
||||||
|
split_constr1(T);
|
||||||
_ ->
|
_ ->
|
||||||
[C]
|
[C]
|
||||||
end;
|
end;
|
||||||
@ -2068,6 +2138,7 @@ filter_obvious([H|T], Acc) ->
|
|||||||
solve(Env, AST0, CS) ->
|
solve(Env, AST0, CS) ->
|
||||||
case aeso_smt:scoped(
|
case aeso_smt:scoped(
|
||||||
fun() ->
|
fun() ->
|
||||||
|
declare_constants(),
|
||||||
declare_tuples(find_tuple_sizes(AST0)),
|
declare_tuples(find_tuple_sizes(AST0)),
|
||||||
declare_datatypes(type_defs(Env)),
|
declare_datatypes(type_defs(Env)),
|
||||||
run_solve(CS)
|
run_solve(CS)
|
||||||
@ -2124,7 +2195,7 @@ valid_in({subtype, _Ref, Ann, Env,
|
|||||||
%?DBG("IN\n~s", [aeso_pretty:pp(predicate, strip_typed(pred_of(Assg, Env1)))]),
|
%?DBG("IN\n~s", [aeso_pretty:pp(predicate, strip_typed(pred_of(Assg, Env1)))]),
|
||||||
SimpAssump = simplify_pred(Assg, Env1,
|
SimpAssump = simplify_pred(Assg, Env1,
|
||||||
pred_of(Assg, Env1) ++ AssumpPred),
|
pred_of(Assg, Env1) ++ AssumpPred),
|
||||||
add_error({contradict, {Ann, strip_typed(SimpAssump), strip_typed(ConclPred)}})
|
add_error({contradict, {[_Ref|Ann], strip_typed(SimpAssump), strip_typed(ConclPred)}})
|
||||||
end;
|
end;
|
||||||
valid_in({subtype, _Ref, _, Env,
|
valid_in({subtype, _Ref, _, Env,
|
||||||
{refined_t, _, SubId, _, SubPredVar},
|
{refined_t, _, SubId, _, SubPredVar},
|
||||||
@ -2188,6 +2259,9 @@ check_reachable(_, []) ->
|
|||||||
|
|
||||||
%% -- SMT Solving --------------------------------------------------------------
|
%% -- SMT Solving --------------------------------------------------------------
|
||||||
|
|
||||||
|
declare_constants() ->
|
||||||
|
aeso_smt:declare_const({var, "Call.caller"}, {var, "Int"}).
|
||||||
|
|
||||||
declare_tuples([]) ->
|
declare_tuples([]) ->
|
||||||
ok;
|
ok;
|
||||||
declare_tuples([N|Rest]) ->
|
declare_tuples([N|Rest]) ->
|
||||||
@ -2314,6 +2388,8 @@ is_smt_type(Expr) ->
|
|||||||
false
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
type_to_smt({empty_sub, _, T}) ->
|
||||||
|
type_to_smt(T);
|
||||||
type_to_smt({refined_t, _, _, T, _}) ->
|
type_to_smt({refined_t, _, _, T, _}) ->
|
||||||
type_to_smt(T);
|
type_to_smt(T);
|
||||||
type_to_smt(?bool_tp) ->
|
type_to_smt(?bool_tp) ->
|
||||||
@ -2373,6 +2449,8 @@ expr_to_smt({bool, _, false}) ->
|
|||||||
{var, "false"};
|
{var, "false"};
|
||||||
expr_to_smt({int, _, I}) ->
|
expr_to_smt({int, _, I}) ->
|
||||||
{int, I};
|
{int, I};
|
||||||
|
expr_to_smt({account_pubkey, _, Key}) ->
|
||||||
|
{int, binary:decode_unsigned(Key)};
|
||||||
expr_to_smt({string, _, S}) ->
|
expr_to_smt({string, _, S}) ->
|
||||||
%% FIXME this sucks as it doesn't play well with the concatenation
|
%% FIXME this sucks as it doesn't play well with the concatenation
|
||||||
{int, binary:decode_unsigned(crypto:hash(md5, S))};
|
{int, binary:decode_unsigned(crypto:hash(md5, S))};
|
||||||
@ -2678,6 +2756,8 @@ a_normalize_to_simpl(Expr = {con, _, _}, Type, Decls) ->
|
|||||||
{?typed(Expr, Type), Decls};
|
{?typed(Expr, Type), Decls};
|
||||||
a_normalize_to_simpl(Expr = {qcon, _, _}, Type, Decls) ->
|
a_normalize_to_simpl(Expr = {qcon, _, _}, Type, Decls) ->
|
||||||
{?typed(Expr, Type), Decls};
|
{?typed(Expr, Type), Decls};
|
||||||
|
a_normalize_to_simpl(Expr = {account_pubkey, _, _}, Type, Decls) ->
|
||||||
|
{?typed(Expr, Type), Decls};
|
||||||
a_normalize_to_simpl(Expr = {int, _, _}, Type, Decls) ->
|
a_normalize_to_simpl(Expr = {int, _, _}, Type, Decls) ->
|
||||||
{?typed(Expr, Type), Decls};
|
{?typed(Expr, Type), Decls};
|
||||||
a_normalize_to_simpl(Expr = {bool, _, _}, Type, Decls) ->
|
a_normalize_to_simpl(Expr = {bool, _, _}, Type, Decls) ->
|
||||||
@ -2862,6 +2942,16 @@ purify_expr({app, Ann, Fun = ?typed_p({id, _, FName}), Args}, T, ST)
|
|||||||
when FName == "require" orelse FName == "abort" ->
|
when FName == "require" orelse FName == "abort" ->
|
||||||
Args1 = [drop_purity(purify_expr(A, ST)) || A <- Args],
|
Args1 = [drop_purity(purify_expr(A, ST)) || A <- Args],
|
||||||
{pure, ?typed({app, Ann, Fun, Args1}, T)};
|
{pure, ?typed({app, Ann, Fun, Args1}, T)};
|
||||||
|
%% Spend
|
||||||
|
purify_expr({app, Ann, Fun = ?typed_p({qid, _, ["Chain", "spend"]}), [Addr, Value]}, T, ST) ->
|
||||||
|
{pure, Addr1} = purify_expr(Addr, ST),
|
||||||
|
{pure, Value1} = purify_expr(Value, ST),
|
||||||
|
{impure, wrap_state(
|
||||||
|
?typed({app, Ann, Fun, [Addr1, Value1]}, purify_type(T, ST)),
|
||||||
|
ST#purifier_st{
|
||||||
|
balance = ?typed(?op(Ann, ST#purifier_st.balance, '-', Value1),
|
||||||
|
?d_nonneg_int(Ann))}
|
||||||
|
)};
|
||||||
%% Put
|
%% Put
|
||||||
purify_expr({app, _, ?typed_p({qid, QAnn, [_, "put"]}), [State]}, T, ST) ->
|
purify_expr({app, _, ?typed_p({qid, QAnn, [_, "put"]}), [State]}, T, ST) ->
|
||||||
{pure, ?typed_p(State1)} = purify_expr(State, ST),
|
{pure, ?typed_p(State1)} = purify_expr(State, ST),
|
||||||
@ -3055,8 +3145,7 @@ purify_expr_to_pure(Expr, ST) ->
|
|||||||
%% -- Errors -------------------------------------------------------------------
|
%% -- Errors -------------------------------------------------------------------
|
||||||
|
|
||||||
pp_error({contradict, {Ann, Assump, Promise}}) ->
|
pp_error({contradict, {Ann, Assump, Promise}}) ->
|
||||||
io_lib:format("Could not prove the promise at ~s ~p:~p\n"
|
io_lib:format("Could not prove the promise at ~s ~p:~p ~s:\n"
|
||||||
"~s:\n"
|
|
||||||
" ~s\n"
|
" ~s\n"
|
||||||
"from the assumption\n"
|
"from the assumption\n"
|
||||||
" ~s\n",
|
" ~s\n",
|
||||||
|
@ -289,7 +289,8 @@ type(T = {tvar, _, _}) -> name(T);
|
|||||||
|
|
||||||
type(T) -> dep_type(T).
|
type(T) -> dep_type(T).
|
||||||
|
|
||||||
|
dep_type({empty_sub, _, T}) ->
|
||||||
|
beside([text("<"), type(T), text(">")]);
|
||||||
dep_type({refined_t, _, Id, BaseType, []}) ->
|
dep_type({refined_t, _, Id, BaseType, []}) ->
|
||||||
beside(
|
beside(
|
||||||
[ text("{")
|
[ text("{")
|
||||||
|
@ -30,11 +30,11 @@ unsetup(_) ->
|
|||||||
|
|
||||||
hagia_test_() ->
|
hagia_test_() ->
|
||||||
?IF(os:find_executable("z3") == false, [], % This turns off hagia tests on machines that don't have Z3
|
?IF(os:find_executable("z3") == false, [], % This turns off hagia tests on machines that don't have Z3
|
||||||
{timeout, 100000000,
|
{timeout, 10000000000000000,
|
||||||
{inorder,
|
{inorder,
|
||||||
{foreach, local, fun setup/0, fun unsetup/1,
|
{foreach, local, fun setup/0, fun unsetup/1,
|
||||||
[ {timeout, 5, smt_solver_test_group()}
|
[ {timeout, 5, smt_solver_test_group()}
|
||||||
, {timeout, 1000000, refiner_test_group()}
|
, {timeout, 1000000000000000, refiner_test_group()}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}}).
|
}}).
|
||||||
@ -54,7 +54,7 @@ smt_solver_test_group() ->
|
|||||||
|
|
||||||
refiner_test_group() ->
|
refiner_test_group() ->
|
||||||
[ {"Testing type refinement of the " ++ ContractName ++ ".aes contract",
|
[ {"Testing type refinement of the " ++ ContractName ++ ".aes contract",
|
||||||
{timeout, 600,
|
{timeout, 60000,
|
||||||
fun() ->
|
fun() ->
|
||||||
try {run_refine("hagia/" ++ ContractName), Expect} of
|
try {run_refine("hagia/" ++ ContractName), Expect} of
|
||||||
{{ok, {Env, AST}}, {success, Assertions}} ->
|
{{ok, {Env, AST}}, {success, Assertions}} ->
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
include "List.aes"
|
contract XD =
|
||||||
|
|
||||||
contract C =
|
entrypoint gasdas() = 123
|
||||||
payable stateful entrypoint split(targets : list(address)) =
|
|
||||||
require(targets != [], "NO_TARGETS")
|
|
||||||
let value_per_person = Call.value / List.length(targets)
|
|
||||||
spend_to_all(value_per_person, targets)
|
|
||||||
|
|
||||||
stateful function
|
function f() = Some(() => ())
|
||||||
spend_to_all : ({v : int | v >= 0}, list(address)) => unit
|
|
||||||
spend_to_all(_, []) = ()
|
|
||||||
spend_to_all(value, addr::rest) =
|
|
||||||
require(value < Contract.balance, "")
|
|
||||||
Chain.spend(addr, value)
|
|
||||||
spend_to_all(value, rest)
|
|
Loading…
x
Reference in New Issue
Block a user