Implement env getters and setters

This commit is contained in:
Gaith Hallak 2023-04-26 12:55:23 +03:00
parent 9f8f3c2ac8
commit 4c90b00fd0

View File

@ -225,6 +225,64 @@ get_named_argument_constraint_name(#named_argument_constraint{name = Name}) -> N
get_named_argument_constraint_args(#named_argument_constraint{args = Args}) -> Args.
get_named_argument_constraint_type(#named_argument_constraint{type = Type}) -> Type.
%% -- Env getters ------------------------------------------------------------
tc_env_contract_parents(#env{contract_parents = ContractParents}) ->
ContractParents.
tc_env_unify_throws(#env{unify_throws = UnifyThrows}) ->
UnifyThrows.
tc_env_namespace(#env{namespace = Namespace}) ->
Namespace.
tc_env_current_function(#env{current_function = CurrentFunction}) ->
CurrentFunction.
tc_env_in_pattern(#env{in_pattern = InPattern}) ->
InPattern.
tc_env_in_guard(#env{in_guard = InGuard}) ->
InGuard.
tc_env_stateful(#env{stateful = Stateful}) ->
Stateful.
tc_env_used_namespaces(#env{used_namespaces = UsedNamespaces}) ->
UsedNamespaces.
tc_env_what(#env{what = What}) ->
What.
tc_env_typevars(#env{typevars = Typevars}) ->
Typevars.
%% -- Env setters ------------------------------------------------------------
tc_env_set_in_pattern(InPattern, Env) ->
Env#env{in_pattern = InPattern}.
tc_env_set_in_guard(InGuard, Env) ->
Env#env{in_guard = InGuard}.
tc_env_set_used_namespaces(UsedNamespaces, Env) ->
Env#env{used_namespaces = UsedNamespaces}.
tc_env_set_current_const(CurrentConst, Env) ->
Env#env{current_const = CurrentConst}.
tc_env_set_current_function(CurrentFunction, Env) ->
Env#env{current_function = CurrentFunction}.
tc_env_set_stateful(Stateful, Env) ->
Env#env{stateful = Stateful}.
tc_env_set_what(What, Env) ->
Env#env{what = What}.
tc_env_set_contract_parents(ContractParents, Env) ->
Env#env{contract_parents = ContractParents}.
%% -- Environment manipulation -----------------------------------------------
-spec switch_scope(qname(), env()) -> env().
@ -273,14 +331,6 @@ bind_vars([{X, T} | Vars], Env) ->
bind_tvars(Xs, Env) ->
Env#env{ typevars = [X || {tvar, _, X} <- Xs] }.
-spec check_tvar(env(), aeso_syntax:tvar()) -> aeso_syntax:tvar() | no_return().
check_tvar(#env{ typevars = TVars}, T = {tvar, _, X}) ->
case TVars == unrestricted orelse lists:member(X, TVars) of
true -> ok;
false -> type_error({unbound_type, T})
end,
T.
-spec bind_fun(name(), type() | typesig(), env()) -> env().
bind_fun(X, Type, Env) ->
case lookup_env(Env, term, [], [X]) of
@ -589,6 +639,9 @@ is_private(Ann) -> proplists:get_value(private, Ann, false).
%% -- The rest ---------------------------------------------------------------
-spec empty_env() -> env().
empty_env() -> #env{}.
%% Environment containing language primitives
-spec global_env() -> env().
global_env() ->
@ -978,9 +1031,10 @@ infer1(Env, [], Acc, _Options) -> {Env, lists:reverse(Acc)};
infer1(Env0, [Contract0 = {Contract, Ann, ConName, Impls, Code} | Rest], Acc, Options)
when ?IS_CONTRACT_HEAD(Contract) ->
%% do type inference on each contract independently.
Env = Env0#env{ contract_parents = maps:put(name(ConName),
[name(Impl) || Impl <- Impls],
Env0#env.contract_parents) },
Parents = maps:put(name(ConName),
[name(Impl) || Impl <- Impls],
tc_env_contract_parents(Env0)),
Env = tc_env_set_contract_parents(Parents, Env0),
check_scope_name_clash(Env, contract, ConName),
What = case Contract of
contract_main -> contract;
@ -1130,7 +1184,7 @@ infer_contract(Env0, What, Defs0, Options) ->
false -> Defs01
end,
destroy_and_report_type_errors(Env0),
Env = Env0#env{ what = What },
Env = tc_env_set_what(What, Env0),
Kind = fun({type_def, _, _, _, _}) -> type;
({letfun, _, _, _, _, _}) -> function;
({fun_clauses, _, _, _, _}) -> function;
@ -1140,10 +1194,10 @@ infer_contract(Env0, What, Defs0, Options) ->
(_) -> unexpected
end,
Get = fun(K, In) -> [ Def || Def <- In, Kind(Def) == K ] end,
OldUsedNamespaces = Env#env.used_namespaces,
OldUsedNamespaces = tc_env_used_namespaces(Env),
Env01 = check_usings(Env, Get(using, Defs)),
{Env1, TypeDefs} = check_typedefs(Env01, Get(type, Defs)),
when_warning(warn_unused_typedefs, fun() -> potential_unused_typedefs(Env#env.namespace, TypeDefs) end),
when_warning(warn_unused_typedefs, fun() -> potential_unused_typedefs(tc_env_namespace(Env), TypeDefs) end),
create_type_errors(),
check_unexpected(Get(unexpected, Defs)),
Env2 =
@ -1163,14 +1217,14 @@ infer_contract(Env0, What, Defs0, Options) ->
FunBind = fun({letfun, Ann, {id, _, Fun}, _, _, _}) -> {Fun, {tuple_t, Ann, []}};
({fun_clauses, Ann, {id, _, Fun}, _, _}) -> {Fun, {tuple_t, Ann, []}} end,
FunName = fun(Def) -> {Name, _} = FunBind(Def), Name end,
_ = bind_funs(lists:map(FunBind, Functions), #env{}),
_ = bind_funs(lists:map(FunBind, Functions), empty_env()),
FunMap = maps:from_list([ {FunName(Def), Def} || Def <- Functions ]),
check_reserved_entrypoints(FunMap),
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap),
SCCs = aeso_utils:scc(DepGraph),
{Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []),
%% Remove namespaces used in the current namespace
Env5 = Env4#env{ used_namespaces = OldUsedNamespaces },
Env5 = tc_env_set_used_namespaces(OldUsedNamespaces, Env4),
%% Check that `init` doesn't read or write the state and that `init` is not missing
check_state(Env4, Defs1),
%% Check that entrypoints have first-order arg types and return types
@ -1199,11 +1253,11 @@ expose_internals(Defs, What) ->
].
-spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
check_typedefs(Env = #env{ namespace = Ns }, Defs) ->
check_typedefs(Env, Defs) ->
create_type_errors(),
GetName = fun({type_def, _, {id, _, Name}, _, _}) -> Name end,
TypeMap = maps:from_list([ {GetName(Def), Def} || Def <- Defs ]),
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_types(Ns, Def) end, TypeMap),
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_types(tc_env_namespace(Env), Def) end, TypeMap),
SCCs = aeso_utils:scc(DepGraph),
{Env1, Defs1} = check_typedef_sccs(Env, TypeMap, SCCs, []),
destroy_and_report_type_errors(Env),
@ -1227,14 +1281,14 @@ check_typedef_sccs(Env, TypeMap, [{acyclic, Name} | SCCs], Acc) ->
type_error({empty_record_definition, Ann, Name}),
check_typedef_sccs(Env1, TypeMap, SCCs, Acc1);
{record_t, Fields} ->
aeso_tc_ets_manager:ets_insert(type_vars_variance, {Env#env.namespace ++ qname(D),
aeso_tc_ets_manager:ets_insert(type_vars_variance, {tc_env_namespace(Env) ++ qname(D),
infer_type_vars_variance(Xs, Fields)}),
%% check_type to get qualified name
RecTy = check_type(Env1, app_t(Ann, D, Xs)),
Env2 = check_fields(Env1, TypeMap, RecTy, Fields),
check_typedef_sccs(Env2, TypeMap, SCCs, Acc1);
{variant_t, Cons} ->
aeso_tc_ets_manager:ets_insert(type_vars_variance, {Env#env.namespace ++ qname(D),
aeso_tc_ets_manager:ets_insert(type_vars_variance, {tc_env_namespace(Env) ++ qname(D),
infer_type_vars_variance(Xs, Cons)}),
Target = check_type(Env1, app_t(Ann, D, Xs)),
ConType = fun([]) -> Target; (Args) -> {type_sig, Ann, none, [], Args, Target} end,
@ -1304,14 +1358,14 @@ opposite_variance(contravariant) -> covariant;
opposite_variance(bivariant) -> bivariant.
-spec check_constants(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
check_constants(Env = #env{ what = What }, Consts) ->
check_constants(Env, Consts) ->
HasValidId = fun({letval, _, {id, _, _}, _}) -> true;
({letval, _, {typed, _, {id, _, _}, _}, _}) -> true;
(_) -> false
end,
{Valid, Invalid} = lists:partition(HasValidId, Consts),
[ type_error({invalid_const_id, aeso_syntax:get_ann(Pat)}) || {letval, _, Pat, _} <- Invalid ],
[ type_error({illegal_const_in_interface, Ann}) || {letval, Ann, _, _} <- Valid, What == contract_interface ],
[ type_error({illegal_const_in_interface, Ann}) || {letval, Ann, _, _} <- Valid, tc_env_what(Env) == contract_interface ],
when_warning(warn_unused_constants, fun() -> potential_unused_constants(Env, Valid) end),
ConstMap = maps:from_list([ {name(Id), Const} || Const = {letval, _, Id, _} <- Valid ]),
DepGraph = maps:map(fun(_, Const) -> aeso_syntax_utils:used_ids(Const) end, ConstMap),
@ -1320,7 +1374,7 @@ check_constants(Env = #env{ what = What }, Consts) ->
check_usings(Env, []) ->
Env;
check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con, Alias, Parts} | Rest]) ->
check_usings(Env, [{using, Ann, Con, Alias, Parts} | Rest]) ->
AliasName = case Alias of
none ->
none;
@ -1354,7 +1408,7 @@ check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con,
destroy_and_report_type_errors(Env)
end
end,
check_usings(Env#env{ used_namespaces = UsedNamespaces ++ [Nsp] }, Rest)
check_usings(tc_env_set_used_namespaces(tc_env_used_namespaces(Env) ++ [Nsp], Env), Rest)
end;
check_usings(Env, Using = {using, _, _, _, _}) ->
check_usings(Env, [Using]).
@ -1476,6 +1530,15 @@ check_type(_Env, {args_t, Ann, Ts}, _) ->
type_error({new_tuple_syntax, Ann, Ts}),
{tuple_t, Ann, Ts}.
-spec check_tvar(env(), aeso_syntax:tvar()) -> aeso_syntax:tvar() | no_return().
check_tvar(Env, T = {tvar, _, X}) ->
TVars = tc_env_typevars(Env),
case TVars == unrestricted orelse lists:member(X, TVars) of
true -> ok;
false -> type_error({unbound_type, T})
end,
T.
ensure_base_type(Type, Arity) ->
[ type_error({wrong_type_arguments, Type, Arity, 0}) || Arity /= 0 ],
ok.
@ -1564,7 +1627,7 @@ check_repeated_constructors(Cons) ->
-spec check_sccs(env(), #{ name() => aeso_syntax:decl() }, [{acyclic, name()} | {cyclic, [name()]}], [aeso_syntax:decl()]) ->
{env(), [aeso_syntax:decl()]}.
check_sccs(Env, _, [], Acc) -> {Env, lists:reverse(Acc)};
check_sccs(Env = #env{}, Funs, [{acyclic, X} | SCCs], Acc) ->
check_sccs(Env, Funs, [{acyclic, X} | SCCs], Acc) ->
case maps:get(X, Funs, undefined) of
undefined -> %% Previously defined function
check_sccs(Env, Funs, SCCs, Acc);
@ -1573,7 +1636,7 @@ check_sccs(Env = #env{}, Funs, [{acyclic, X} | SCCs], Acc) ->
Env1 = bind_fun(X, TypeSig, Env),
check_sccs(Env1, Funs, SCCs, [Def1 | Acc])
end;
check_sccs(Env = #env{}, Funs, [{cyclic, Xs} | SCCs], Acc) ->
check_sccs(Env, Funs, [{cyclic, Xs} | SCCs], Acc) ->
Defs = [ maps:get(X, Funs) || X <- Xs ],
{TypeSigs, Defs1} = infer_letrec(Env, Defs),
Env1 = bind_funs(TypeSigs, Env),
@ -1673,10 +1736,10 @@ infer_letrec(Env, Defs) ->
[print_typesig(S) || S <- TypeSigs],
{TypeSigs, NewDefs}.
infer_letfun(Env = #env{ namespace = Namespace }, {fun_clauses, Ann, Fun = {id, _, Name}, Type, Clauses}) ->
infer_letfun(Env, {fun_clauses, Ann, Fun = {id, _, Name}, Type, Clauses}) ->
when_warning(warn_unused_stateful, fun() -> potential_unused_stateful(Ann, Fun) end),
when_warning(warn_unused_functions,
fun() -> potential_unused_function(Env, Ann, Namespace ++ qname(Fun), Fun) end),
fun() -> potential_unused_function(Env, Ann, tc_env_namespace(Env) ++ qname(Fun), Fun) end),
Type1 = check_type(Env, Type),
{NameSigs, Clauses1} = lists:unzip([ infer_letfun1(Env, Clause) || Clause <- Clauses ]),
{_, Sigs = [Sig | _]} = lists:unzip(NameSigs),
@ -1685,21 +1748,21 @@ infer_letfun(Env = #env{ namespace = Namespace }, {fun_clauses, Ann, Fun = {id,
unify(Env, ClauseT, Type1, {check_typesig, Name, ClauseT, Type1})
end || ClauseSig <- Sigs ],
{{Name, Sig}, desugar_clauses(Ann, Fun, Sig, Clauses1)};
infer_letfun(Env = #env{ namespace = Namespace }, LetFun = {letfun, Ann, Fun, _, _, _}) ->
infer_letfun(Env, LetFun = {letfun, Ann, Fun, _, _, _}) ->
when_warning(warn_unused_stateful, fun() -> potential_unused_stateful(Ann, Fun) end),
when_warning(warn_unused_functions, fun() -> potential_unused_function(Env, Ann, Namespace ++ qname(Fun), Fun) end),
when_warning(warn_unused_functions, fun() -> potential_unused_function(Env, Ann, tc_env_namespace(Env) ++ qname(Fun), Fun) end),
{{Name, Sig}, Clause} = infer_letfun1(Env, LetFun),
{{Name, Sig}, desugar_clauses(Ann, Fun, Sig, [Clause])}.
infer_letfun1(Env0 = #env{ namespace = NS }, {letfun, Attrib, Fun = {id, NameAttrib, Name}, Args, What, GuardedBodies}) ->
Env = Env0#env{ stateful = aeso_syntax:get_ann(stateful, Attrib, false),
current_function = Fun },
infer_letfun1(Env0, {letfun, Attrib, Fun = {id, NameAttrib, Name}, Args, What, GuardedBodies}) ->
Env1 = tc_env_set_stateful(aeso_syntax:get_ann(stateful, Attrib, false), Env0),
Env = tc_env_set_current_function(Fun, Env1),
{NewEnv, {typed, _, {tuple, _, TypedArgs}, {tuple_t, _, ArgTypes}}} = infer_pattern(Env, {tuple, [{origin, system} | NameAttrib], Args}),
when_warning(warn_unused_variables, fun() -> potential_unused_variables(NS, Name, free_vars(Args)) end),
when_warning(warn_unused_variables, fun() -> potential_unused_variables(tc_env_namespace(Env0), Name, free_vars(Args)) end),
ExpectedType = check_type(Env, arg_type(NameAttrib, What)),
InferGuardedBodies = fun({guarded, Ann, Guards, Body}) ->
NewGuards = lists:map(fun(Guard) ->
check_expr(NewEnv#env{ in_guard = true }, Guard, {id, Attrib, "bool"})
check_expr(tc_env_set_in_guard(true, NewEnv), Guard, {id, Attrib, "bool"})
end, Guards),
NewBody = check_expr(NewEnv, Body, ExpectedType),
{guarded, Ann, NewGuards, NewBody}
@ -1761,29 +1824,38 @@ lookup_name(Env = #env{ namespace = NS, current_function = CurFn }, As, Id, Opti
{set_qname(QId, Id), Ty1}
end.
check_stateful(#env{ in_guard = true }, Id, Type = {type_sig, _, _, _, _, _}) ->
case aeso_syntax:get_ann(stateful, Type, false) of
false -> ok;
true ->
type_error({stateful_not_allowed_in_guards, Id})
end;
check_stateful(#env{ stateful = false, current_function = Fun }, Id, Type = {type_sig, _, _, _, _, _}) ->
case aeso_syntax:get_ann(stateful, Type, false) of
false -> ok;
true ->
type_error({stateful_not_allowed, Id, Fun})
end;
check_stateful(#env { current_function = Fun }, _Id, _Type) ->
when_warning(warn_unused_stateful, fun() -> used_stateful(Fun) end),
check_stateful(Env, Id, Type = {type_sig, _, _, _, _, _}) ->
IsStatefulType = aeso_syntax:get_ann(stateful, Type, false),
IsStatefulType andalso (check_stateful_not_in_guard(Env, Id) andalso check_stateful_in_stateful_fun(Env, Id)),
ok;
check_stateful(Env, _Id, _Type) ->
when_warning(warn_unused_stateful, fun() -> used_stateful(tc_env_current_function(Env)) end),
ok.
check_stateful_not_in_guard(Env, Id) ->
case tc_env_in_guard(Env) of
false -> true;
true ->
type_error({stateful_not_allowed_in_guards, Id}),
false
end.
check_stateful_in_stateful_fun(Env, Id) ->
case tc_env_stateful(Env) of
true -> true;
false ->
type_error({stateful_not_allowed, Id, tc_env_current_function(Env)}),
false
end.
%% Hack: don't allow passing the 'value' named arg if not stateful. This only
%% works since the user can't create functions with named arguments.
check_stateful_named_arg(#env{ stateful = Stateful, current_function = Fun }, {id, _, "value"}, Default) ->
check_stateful_named_arg(Env, {id, _, "value"}, Default) ->
case Default of
{int, _, 0} -> ok;
_ ->
case Stateful of
Fun = tc_env_current_function(Env),
case tc_env_stateful(Env) of
true -> when_warning(warn_unused_stateful, fun() -> used_stateful(Fun) end);
false -> type_error({value_arg_not_allowed, Default, Fun})
end
@ -1821,7 +1893,7 @@ is_monomorphic(Tup) when is_tuple(Tup) -> is_monomorphic(tuple_to_list(Tup));
is_monomorphic(_) -> true.
check_state_init(Env) ->
Top = Env#env.namespace,
Top = tc_env_namespace(Env),
StateType = lookup_type(Env, {id, [{origin, system}], "state"}),
case unfold_types_in_type(Env, StateType) of
false ->
@ -1836,7 +1908,7 @@ check_state_init(Env) ->
%% Check that `init` doesn't read or write the state and that `init` is defined
%% when the state type is not unit
check_state(Env, Defs) ->
Top = Env#env.namespace,
Top = tc_env_namespace(Env),
GetState = Top ++ ["state"],
SetState = Top ++ ["put"],
Init = Top ++ ["init"],
@ -2029,7 +2101,7 @@ infer_expr(Env, {record, Attrs, Fields}) ->
add_constraint([ #record_create_constraint{
record_t = RecordType1,
fields = [ FieldName || {field, _, [{proj, _, FieldName}], _} <- Fields ],
context = Attrs } || not Env#env.in_pattern ] ++
context = Attrs } || not tc_env_in_pattern(Env) ] ++
[begin
[{proj, _, FieldName}] = LV,
#field_constraint{
@ -2310,23 +2382,23 @@ infer_pattern(Env, Pattern) ->
[] -> ok;
Nonlinear -> type_error({non_linear_pattern, Pattern, lists:usort(Nonlinear)})
end,
NewEnv = bind_vars([{Var, fresh_uvar(Ann1)} || Var = {id, Ann1, _} <- Vars], Env#env{ in_pattern = true }),
NewEnv = bind_vars([{Var, fresh_uvar(Ann1)} || Var = {id, Ann1, _} <- Vars], tc_env_set_in_pattern(true, Env)),
NewPattern = infer_expr(NewEnv, Pattern),
{NewEnv#env{ in_pattern = Env#env.in_pattern }, NewPattern}.
{tc_env_set_in_pattern(tc_env_in_pattern(Env), NewEnv), NewPattern}.
infer_case(Env = #env{ namespace = NS, current_function = FunId }, Attrs, Pattern, ExprType, GuardedBranches, SwitchType) ->
infer_case(Env, Attrs, Pattern, ExprType, GuardedBranches, SwitchType) ->
{NewEnv, NewPattern = {typed, _, _, PatType}} = infer_pattern(Env, Pattern),
%% Make sure we are inside a function before warning about potentially unused var
[ when_warning(warn_unused_variables,
fun() -> potential_unused_variables(NS, Fun, free_vars(Pattern)) end)
|| {id, _, Fun} <- [FunId] ],
fun() -> potential_unused_variables(tc_env_namespace(Env), Fun, free_vars(Pattern)) end)
|| {id, _, Fun} <- [tc_env_current_function(Env)] ],
InferGuardedBranches = fun({guarded, Ann, Guards, Branch}) ->
NewGuards = lists:map(fun(Guard) ->
check_expr(NewEnv#env{ in_guard = true }, Guard, {id, Attrs, "bool"})
check_expr(tc_env_set_in_guard(true, NewEnv), Guard, {id, Attrs, "bool"})
end, Guards),
NewBranch = check_expr(NewEnv#env{ in_pattern = false }, Branch, SwitchType),
NewBranch = check_expr(tc_env_set_in_pattern(false, NewEnv), Branch, SwitchType),
{guarded, Ann, NewGuards, NewBranch}
end,
NewGuardedBranches = lists:map(InferGuardedBranches, GuardedBranches),
@ -2357,12 +2429,12 @@ infer_block(Env, Attrs, [E|Rest], BlockType) ->
infer_const(Env, {letval, Ann, TypedId = {typed, _, Id = {id, _, _}, Type}, Expr}) ->
check_valid_const_expr(Expr) orelse type_error({invalid_const_expr, Id}),
NewExpr = check_expr(Env#env{ current_const = Id }, Expr, Type),
NewExpr = check_expr(tc_env_set_current_const(Id, Env), Expr, Type),
{letval, Ann, TypedId, NewExpr};
infer_const(Env, {letval, Ann, Id = {id, AnnId, _}, Expr}) ->
check_valid_const_expr(Expr) orelse type_error({invalid_const_expr, Id}),
create_constraints(),
NewExpr = {typed, _, _, Type} = infer_expr(Env#env{ current_const = Id }, Expr),
NewExpr = {typed, _, _, Type} = infer_expr(tc_env_set_current_const(Id, Env), Expr),
solve_then_destroy_and_report_unsolved_constraints(Env),
IdType = setelement(2, Type, AnnId),
NewId = {typed, aeso_syntax:get_ann(Id), Id, IdType},
@ -2985,10 +3057,10 @@ unify1(_Env, {uvar, _, _}, {fun_t, _, _, var_args, _}, _Variance, When) ->
unify1(Env, {uvar, A, R}, T, _Variance, When) ->
case occurs_check(R, T) of
true ->
if
Env#env.unify_throws ->
cannot_unify({uvar, A, R}, T, none, When);
case tc_env_unify_throws(Env) of
true ->
cannot_unify({uvar, A, R}, T, none, When);
false ->
ok
end,
false;
@ -3017,8 +3089,8 @@ unify1(Env, A = {con, _, NameA}, B = {con, _, NameB}, Variance, When) ->
case is_subtype(Env, NameA, NameB, Variance) of
true -> true;
false ->
if
Env#env.unify_throws ->
case tc_env_unify_throws(Env) of
true ->
IsSubtype = is_subtype(Env, NameA, NameB, contravariant) orelse
is_subtype(Env, NameA, NameB, covariant),
Cxt = case IsSubtype of
@ -3026,7 +3098,7 @@ unify1(Env, A = {con, _, NameA}, B = {con, _, NameB}, Variance, When) ->
false -> none
end,
cannot_unify(A, B, Cxt, When);
true ->
false ->
ok
end,
false
@ -3076,10 +3148,10 @@ unify1(Env, {app_t, _, T, []}, B, Variance, When) ->
unify1(Env, A, {app_t, _, T, []}, Variance, When) ->
unify0(Env, A, T, Variance, When);
unify1(Env, A, B, _Variance, When) ->
if
Env#env.unify_throws ->
cannot_unify(A, B, none, When);
case tc_env_unify_throws(Env) of
true ->
cannot_unify(A, B, none, When);
false ->
ok
end,
false.
@ -3094,7 +3166,7 @@ is_subtype(Env, NameA, NameB, bivariant) ->
is_subtype(Env, NameA, NameB) orelse is_subtype(Env, NameB, NameA).
is_subtype(Env, Child, Base) ->
Parents = maps:get(Child, Env#env.contract_parents, []),
Parents = maps:get(Child, tc_env_contract_parents(Env), []),
if
Child == Base ->
true;