Make interfaces declare functions from extended interfaces
This commit is contained in:
parent
5624279d6d
commit
94c8bc3671
@ -855,7 +855,7 @@ infer1(Env0, [{Contract, Ann, ConName, Impls, Code} | Rest], Acc, Options)
|
||||
end,
|
||||
{Env1, Code1} = infer_contract_top(push_scope(contract, ConName, Env), What, Code, Options),
|
||||
Contract1 = {Contract, Ann, ConName, Impls, Code1},
|
||||
check_implemented_interfaces(Env1, Contract1, What, Acc),
|
||||
check_implemented_interfaces(Env1, Contract1, Acc),
|
||||
Env2 = pop_scope(Env1),
|
||||
Env3 = bind_contract(Contract1, Env2),
|
||||
infer1(Env3, Rest, [Contract1 | Acc], Options);
|
||||
@ -871,7 +871,7 @@ infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
|
||||
%% Pragmas are checked in check_modifiers
|
||||
infer1(Env, Rest, Acc, Options).
|
||||
|
||||
check_implemented_interfaces(Env, {_Contract, _Ann, ConName, Impls, Code}, What, DefinedContracts) ->
|
||||
check_implemented_interfaces(Env, {_Contract, _Ann, ConName, Impls, Code}, DefinedContracts) ->
|
||||
create_type_errors(),
|
||||
AllInterfaces = [{name(IName), I} || I = {contract_interface, _, IName, _, _} <- DefinedContracts],
|
||||
ImplsNames = lists:map(fun name/1, Impls),
|
||||
@ -883,43 +883,32 @@ check_implemented_interfaces(Env, {_Contract, _Ann, ConName, Impls, Code}, What,
|
||||
end
|
||||
end, Impls),
|
||||
|
||||
case What of
|
||||
contract ->
|
||||
ImplementedInterfaces = [I || I <- [proplists:get_value(Name, AllInterfaces) || Name <- ImplsNames],
|
||||
I /= undefined],
|
||||
Letfuns = [ Fun || Fun = {letfun, _, _, _, _, _} <- Code ],
|
||||
check_implemented_interfaces1(ImplementedInterfaces, ConName, Letfuns, AllInterfaces);
|
||||
contract_interface ->
|
||||
ok
|
||||
end,
|
||||
Funs = [ Fun || Fun <- Code,
|
||||
element(1, Fun) == letfun orelse element(1, Fun) == fun_decl ],
|
||||
check_implemented_interfaces1(ImplementedInterfaces, ConName, Funs, AllInterfaces),
|
||||
destroy_and_report_type_errors(Env).
|
||||
|
||||
check_implemented_interfaces1(ImplementedInterfaces, ConId, Letfuns, AllInterfaces) ->
|
||||
check_implemented_interfaces1(ImplementedInterfaces, ConId, Letfuns, [], AllInterfaces).
|
||||
|
||||
%% Recursively check that all directly and indirectly referenced interfaces are implemented
|
||||
check_implemented_interfaces1([], _, _, _, _) ->
|
||||
check_implemented_interfaces1([], _, _, _) ->
|
||||
ok;
|
||||
check_implemented_interfaces1([{contract_interface, _, IName, Extensions, Decls} | Interfaces],
|
||||
ConId, Impls, Acc, AllInterfaces) ->
|
||||
case lists:member(name(IName), Acc) of
|
||||
true ->
|
||||
check_implemented_interfaces1(Interfaces, ConId, Impls, Acc, AllInterfaces);
|
||||
false ->
|
||||
check_implemented_interfaces1([{contract_interface, _, IName, _, Decls} | Interfaces],
|
||||
ConId, Impls, AllInterfaces) ->
|
||||
Unmatched = match_impls(Decls, ConId, name(IName), Impls),
|
||||
NewInterfaces = Interfaces ++ [proplists:get_value(name(I), AllInterfaces) || I <- Extensions],
|
||||
check_implemented_interfaces1(NewInterfaces, ConId, Unmatched, [name(IName) | Acc], AllInterfaces)
|
||||
end.
|
||||
check_implemented_interfaces1(Interfaces, ConId, Unmatched, AllInterfaces).
|
||||
|
||||
%% Match the functions of the contract with the interfaces functions, and return unmatched functions
|
||||
match_impls([], _, _, Impls) ->
|
||||
Impls;
|
||||
match_impls([{fun_decl, _, {id, _, FunName}, {fun_t, _, _, ArgsTypes, RetDecl}} | Decls], ConId, IName, Impls) ->
|
||||
match_impls([{fun_decl, _, {id, _, FunName}, FunType = {fun_t, _, _, ArgsTypes, RetDecl}} | Decls], ConId, IName, Impls) ->
|
||||
Match = fun({letfun, _, {id, _, FName}, Args, RetFun, _}) when FName == FunName ->
|
||||
length(ArgsTypes) == length(Args) andalso
|
||||
compare_types(RetDecl, RetFun) andalso
|
||||
lists:all(fun({T1, {typed, _, _, T2}}) -> compare_types(T1, T2) end,
|
||||
lists:zip(ArgsTypes, Args));
|
||||
({fun_decl, _, {id, _, FName}, FunT}) when FName == FunName ->
|
||||
compare_types(FunT, FunType);
|
||||
(_) -> false
|
||||
end,
|
||||
UnmatchedImpls = case lists:search(Match, Impls) of
|
||||
|
@ -205,6 +205,8 @@ compilable_contracts() ->
|
||||
"contract_polymorphism",
|
||||
"contract_polymorphism_multi_interface",
|
||||
"contract_interface_polymorphism",
|
||||
"contract_interface_polymorphism_same_decl_multi_interface",
|
||||
"contract_interface_polymorphism_same_name_same_type",
|
||||
"test" % Custom general-purpose test file. Keep it last on the list.
|
||||
].
|
||||
|
||||
@ -832,23 +834,12 @@ failing_contracts() ->
|
||||
[<<?Pos(1,24)
|
||||
"Trying to implement or extend an undefined interface `Z`">>
|
||||
])
|
||||
, ?TYPE_ERROR(contract_interface_polymorphism_same_decl_multi_interface,
|
||||
[<<?Pos(7,10)
|
||||
"Unimplemented function `f` from the interface `I` in the contract `C`">>
|
||||
])
|
||||
, ?TYPE_ERROR(contract_interface_polymorphism_same_name_same_type,
|
||||
[<<?Pos(7,10)
|
||||
"Unimplemented function `f` from the interface `I1` in the contract `C`">>
|
||||
])
|
||||
, ?TYPE_ERROR(contract_interface_polymorphism_same_name_different_type,
|
||||
[<<?Pos(9,5)
|
||||
"Duplicate definitions of `f` at\n"
|
||||
" - line 8, column 5\n"
|
||||
" - line 9, column 5">>
|
||||
])
|
||||
[<<?Pos(4,20)
|
||||
"Unimplemented function `f` from the interface `I1` in the contract `I2`">>])
|
||||
, ?TYPE_ERROR(contract_polymorphism_missing_implementation,
|
||||
[<<?Pos(7,10)
|
||||
"Unimplemented function `f` from the interface `I1` in the contract `C`">>
|
||||
[<<?Pos(4,20)
|
||||
"Unimplemented function `f` from the interface `I1` in the contract `I2`">>
|
||||
])
|
||||
, ?TYPE_ERROR(contract_polymorphism_same_decl_multi_interface,
|
||||
[<<?Pos(7,10)
|
||||
@ -869,22 +860,22 @@ failing_contracts() ->
|
||||
"Trying to implement or extend an undefined interface `H`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching,
|
||||
[<<?Pos(38,49)
|
||||
[<<?Pos(39,49)
|
||||
"Cannot unify `Cat` and `Animal`\n"
|
||||
"when checking the application of\n"
|
||||
" `g2 : (Cat) => Cat`\n"
|
||||
"to arguments\n"
|
||||
" `x : Animal`">>,
|
||||
<<?Pos(41,43)
|
||||
<<?Pos(42,43)
|
||||
"Cannot unify `Animal` and `Cat`\n"
|
||||
"when checking the type of the expression `g3(x) : Animal` against the expected type `Cat`">>,
|
||||
<<?Pos(50,55)
|
||||
<<?Pos(51,55)
|
||||
"Cannot unify `Animal` and `Cat`\n"
|
||||
"when checking the application of\n"
|
||||
" `g5 : ((Animal) => Animal) => Cat`\n"
|
||||
"to arguments\n"
|
||||
" `x : (Cat) => Cat`">>,
|
||||
<<?Pos(54, 44)
|
||||
<<?Pos(55, 44)
|
||||
"Cannot unify `Animal` and `Cat`\n"
|
||||
"when checking the type of the expression `f6() : option(Animal)` against the expected type `option(Cat)`">>
|
||||
])
|
||||
|
@ -2,6 +2,7 @@ contract interface II =
|
||||
entrypoint f : () => unit
|
||||
|
||||
contract interface I : II =
|
||||
entrypoint f : () => unit
|
||||
entrypoint g : () => unit
|
||||
|
||||
contract C : I =
|
||||
|
@ -2,6 +2,7 @@ contract interface Creature =
|
||||
entrypoint is_alive : () => bool
|
||||
|
||||
contract interface Animal : Creature =
|
||||
entrypoint is_alive : () => bool
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
|
Loading…
x
Reference in New Issue
Block a user