Add variance switching

This commit is contained in:
Gaith Hallak 2021-12-29 13:34:48 +02:00
parent a068822278
commit 01fb058def

View File

@ -134,6 +134,7 @@
, vars = [] :: [{name(), var_info()}] , vars = [] :: [{name(), var_info()}]
, typevars = unrestricted :: unrestricted | [name()] , typevars = unrestricted :: unrestricted | [name()]
, fields = #{} :: #{ name() => [field_info()] } %% fields are global , fields = #{} :: #{ name() => [field_info()] } %% fields are global
, contract_parents = #{} :: #{ name() => [name()] }
, namespace = [] :: qname() , namespace = [] :: qname()
, used_namespaces = [] :: used_namespaces() , used_namespaces = [] :: used_namespaces()
, in_pattern = false :: boolean() , in_pattern = false :: boolean()
@ -832,9 +833,12 @@ infer(Contracts, Options) ->
-spec infer1(env(), [aeso_syntax:decl()], [aeso_syntax:decl()], list(option())) -> -spec infer1(env(), [aeso_syntax:decl()], [aeso_syntax:decl()], list(option())) ->
{env(), [aeso_syntax:decl()]}. {env(), [aeso_syntax:decl()]}.
infer1(Env, [], Acc, _Options) -> {Env, lists:reverse(Acc)}; infer1(Env, [], Acc, _Options) -> {Env, lists:reverse(Acc)};
infer1(Env, [{Contract, Ann, ConName, Impls, Code} | Rest], Acc, Options) infer1(Env0, [{Contract, Ann, ConName, Impls, Code} | Rest], Acc, Options)
when ?IS_CONTRACT_HEAD(Contract) -> when ?IS_CONTRACT_HEAD(Contract) ->
%% do type inference on each contract independently. %% do type inference on each contract independently.
Env = Env0#env{ contract_parents = maps:put(name(ConName),
[name(Impl) || Impl <- Impls],
Env0#env.contract_parents) },
check_scope_name_clash(Env, contract, ConName), check_scope_name_clash(Env, contract, ConName),
What = case Contract of What = case Contract of
contract_main -> contract; contract_main -> contract;
@ -1965,7 +1969,7 @@ infer_case(Env = #env{ namespace = NS, current_function = {id, _, Fun} }, Attrs,
{guarded, Ann, NewGuards, NewBranch} {guarded, Ann, NewGuards, NewBranch}
end, end,
NewGuardedBranches = lists:map(InferGuardedBranches, GuardedBranches), NewGuardedBranches = lists:map(InferGuardedBranches, GuardedBranches),
unify(Env, PatType, ExprType, {case_pat, Pattern, PatType, ExprType}), unify(Env, ExprType, PatType, {case_pat, Pattern, PatType, ExprType}),
{'case', Attrs, NewPattern, NewGuardedBranches}. {'case', Attrs, NewPattern, NewGuardedBranches}.
%% NewStmts = infer_block(Env, Attrs, Stmts, BlockType) %% NewStmts = infer_block(Env, Attrs, Stmts, BlockType)
@ -2647,6 +2651,13 @@ unify1(_Env, {id, _, Name}, {id, _, Name}, _When) ->
true; true;
unify1(_Env, {con, _, Name}, {con, _, Name}, _When) -> unify1(_Env, {con, _, Name}, {con, _, Name}, _When) ->
true; true;
unify1(Env, A = {con, _, Child}, B = {con, _, Base}, When) ->
case is_subtype(Env, Child, Base) of
true -> true;
false ->
cannot_unify(A, B, When),
false
end;
unify1(_Env, {qid, _, Name}, {qid, _, Name}, _When) -> unify1(_Env, {qid, _, Name}, {qid, _, Name}, _When) ->
true; true;
unify1(_Env, {qcon, _, Name}, {qcon, _, Name}, _When) -> unify1(_Env, {qcon, _, Name}, {qcon, _, Name}, _When) ->
@ -2663,8 +2674,8 @@ unify1(_Env, {fun_t, _, _, var_args, _}, {fun_t, _, _, _, _}, When) ->
type_error({unify_varargs, When}); type_error({unify_varargs, When});
unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When) unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When)
when length(Args1) == length(Args2) -> when length(Args1) == length(Args2) ->
unify(Env, Named1, Named2, When) andalso unify(Env, Named2, Named1, When) andalso
unify(Env, Args1, Args2, When) andalso unify(Env, Result1, Result2, When); unify(Env, Args2, Args1, When) andalso unify(Env, Result1, Result2, When);
unify1(Env, {app_t, _, {Tag, _, F}, Args1}, {app_t, _, {Tag, _, F}, Args2}, When) unify1(Env, {app_t, _, {Tag, _, F}, Args1}, {app_t, _, {Tag, _, F}, Args2}, When)
when length(Args1) == length(Args2), Tag == id orelse Tag == qid -> when length(Args1) == length(Args2), Tag == id orelse Tag == qid ->
unify(Env, Args1, Args2, When); unify(Env, Args1, Args2, When);
@ -2685,6 +2696,18 @@ unify1(_Env, A, B, When) ->
cannot_unify(A, B, When), cannot_unify(A, B, When),
false. false.
is_subtype(Env, Child, Base) ->
Parents = maps:get(Child, Env#env.contract_parents, []),
if
Parents == [] ->
false;
true ->
case lists:member(Base, Parents) of
true -> true;
false -> lists:any(fun(Parent) -> is_subtype(Env, Parent, Base) end, Parents)
end
end.
dereference(T = {uvar, _, R}) -> dereference(T = {uvar, _, R}) ->
case ets_lookup(type_vars, R) of case ets_lookup(type_vars, R) of
[] -> [] ->