anchor.diff:  -spec t_unify(erl_type(), erl_type()) -> t_unify_ret().
   
   t_unify(T1, T2) ->
  -  {T, VarMap} = t_unify(T1, T2, []),
  -  {t_subst_kv(T, VarMap), lists:keysort(1, VarMap)}.
  +  {T, VarMap} = t_unify(T1, T2, #{}),
  +  {t_subst(T, VarMap), lists:keysort(1, maps:to_list(VarMap))}.
   
   t_unify(?var(Id) = T, ?var(Id), VarMap) ->
     {T, VarMap};
   t_unify(?var(Id1) = T, ?var(Id2), VarMap) ->
  -  case lists:keyfind(Id1, 1, VarMap) of
  -    false ->
  -      case lists:keyfind(Id2, 1, VarMap) of
  -	false -> {T, [{Id2, T} | VarMap]};
  -	{Id2, Type} -> t_unify(T, Type, VarMap)
  +  case maps:find(Id1, VarMap) of
  +    error ->
  +      case maps:find(Id2, VarMap) of
  +	error -> {T, VarMap#{Id2 => T}};
  +	{ok, Type} -> t_unify(T, Type, VarMap)
         end;
  -    {Id1, Type1} ->
  -      case lists:keyfind(Id2, 1, VarMap) of
  -	false -> {Type1, [{Id2, T} | VarMap]};
  -	{Id2, Type2} -> t_unify(Type1, Type2, VarMap)
  +    {ok, Type1} ->
  +      case maps:find(Id2, VarMap) of
  +	error -> {Type1, VarMap#{Id2 => T}};
  +	{ok, Type2} -> t_unify(Type1, Type2, VarMap)
         end
     end;
   t_unify(?var(Id), Type, VarMap) ->
  -  case lists:keyfind(Id, 1, VarMap) of
  -    false -> {Type, [{Id, Type} | VarMap]};
  -    {Id, VarType} -> t_unify(VarType, Type, VarMap)
  +  case maps:find(Id, VarMap) of
  +    error -> {Type, VarMap#{Id => Type}};
  +    {ok, VarType} -> t_unify(VarType, Type, VarMap)
     end;
   t_unify(Type, ?var(Id), VarMap) ->
  -  case lists:keyfind(Id, 1, VarMap) of
  -    false -> {Type, [{Id, Type} | VarMap]};
  -    {Id, VarType} -> t_unify(VarType, Type, VarMap)
  +  case maps:find(Id, VarMap) of
  +    error -> {Type, VarMap#{Id => Type}};
  +    {ok, VarType} -> t_unify(VarType, Type, VarMap)
     end;
   t_unify(?function(Domain1, Range1), ?function(Domain2, Range2), VarMap) ->
     {Domain, VarMap1} = t_unify(Domain1, Domain2, VarMap),
  
positive.code: 	  ?list(NewContents2, NewTermination, Size)
        end
    end;
  t_subst_dict(?function(Domain, Range), Dict) ->
    ?function(t_subst_dict(Domain, Dict), t_subst_dict(Range, Dict));
  t_subst_dict(?product(Types), Dict) ->
    ?product([t_subst_dict(T, Dict) || T <- Types]);
  t_subst_dict(?tuple(?any, ?any, ?any) = T, _Dict) ->
    T;
  t_subst_dict(?tuple(Elements, _Arity, _Tag), Dict) ->
    t_tuple([t_subst_dict(E, Dict) || E <- Elements]);
  t_subst_dict(?tuple_set(_) = TS, Dict) ->
    t_sup([t_subst_dict(T, Dict) || T <- t_tuple_subtypes(TS)]);
  t_subst_dict(?map(Pairs, DefK, DefV), Dict) ->
    t_map([{K, MNess, t_subst_dict(V, Dict)} || {K, MNess, V} <- Pairs],
  	t_subst_dict(DefK, Dict), t_subst_dict(DefV, Dict));
  t_subst_dict(?opaque(Es), Dict) ->
    List = [Opaque#opaque{args = [t_subst_dict(Arg, Dict) || Arg <- Args],
                          struct = t_subst_dict(S, Dict)} ||
             Opaque = #opaque{args = Args, struct = S} <- set_to_list(Es)],
    ?opaque(ordsets:from_list(List));
  t_subst_dict(?union(List), Dict) ->
    ?union([t_subst_dict(E, Dict) || E <- List]);
  t_subst_dict(T, _Dict) ->
    T.
  
  -spec subst_all_vars_to_any(erl_type()) -> erl_type().
  
  subst_all_vars_to_any(T) ->
    t_subst_kv(T, []).
  
  t_subst_kv(T, KVMap) ->
    case t_has_var(T) of
      true -> t_subst_aux(T, KVMap);
      false -> T
    end.
  
  t_subst_aux(?var(Id), VarMap) ->
    case lists:keyfind(Id, 1, VarMap) of
      false -> ?any;
      {Id, Type} -> Type
    end;
  t_subst_aux(?list(Contents, Termination, Size), VarMap) ->
    case t_subst_aux(Contents, VarMap) of
      ?none -> ?none;
      NewContents ->
        %% Be careful here to make the termination collapse if necessary.
        case t_subst_aux(Termination, VarMap) of
  	?nil -> ?list(NewContents, ?nil, Size);
  	?any -> ?list(NewContents, ?any, Size);
  	Other ->
  	  ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
  	  ?list(NewContents2, NewTermination, Size)
        end
    end;
  t_subst_aux(?function(Domain, Range), VarMap) ->
    ?function(t_subst_aux(Domain, VarMap), t_subst_aux(Range, VarMap));
  t_subst_aux(?product(Types), VarMap) ->
    ?product([t_subst_aux(T, VarMap) || T <- Types]);
  t_subst_aux(?tuple(?any, ?any, ?any) = T, _VarMap) ->
    T;
  t_subst_aux(?tuple(Elements, _Arity, _Tag), VarMap) ->
    t_tuple([t_subst_aux(E, VarMap) || E <- Elements]);
  t_subst_aux(?tuple_set(_) = TS, VarMap) ->
    t_sup([t_subst_aux(T, VarMap) || T <- t_tuple_subtypes(TS)]);
  t_subst_aux(?map(Pairs, DefK, DefV), VarMap) ->
    t_map([{K, MNess, t_subst_aux(V, VarMap)} || {K, MNess, V} <- Pairs],
  	t_subst_aux(DefK, VarMap), t_subst_aux(DefV, VarMap));
  t_subst_aux(?opaque(Es), VarMap) ->
     List = [Opaque#opaque{args = [t_subst_aux(Arg, VarMap) || Arg <- Args],
                           struct = t_subst_aux(S, VarMap)} ||
              Opaque = #opaque{args = Args, struct = S} <- set_to_list(Es)],
     ?opaque(ordsets:from_list(List));
  t_subst_aux(?union(List), VarMap) ->
    ?union([t_subst_aux(E, VarMap) || E <- List]);
  t_subst_aux(T, _VarMap) ->
    T.
  
  %%-----------------------------------------------------------------------------
  
negative.code: %%-----------------------------------------------------------------------------
  %% Substitution of variables
  %%
  
  -type subst_table() :: #{any() => erl_type()}.
  
  -spec t_subst(erl_type(), subst_table()) -> erl_type().
  
  t_subst(T, Map) ->
    case t_has_var(T) of
      true -> t_subst_aux(T, Map);
      false -> T
    end.
  
  -spec subst_all_vars_to_any(erl_type()) -> erl_type().
  
  subst_all_vars_to_any(T) ->
    t_subst(T, #{}).
  
  t_subst_aux(?var(Id), Map) ->
    case maps:find(Id, Map) of
      error -> ?any;
      {ok, Type} -> Type
    end;
  t_subst_aux(?list(Contents, Termination, Size), Map) ->
    case t_subst_aux(Contents, Map) of
      ?none -> ?none;
      NewContents ->
        %% Be careful here to make the termination collapse if necessary.
        case t_subst_aux(Termination, Map) of
  	?nil -> ?list(NewContents, ?nil, Size);
  	?any -> ?list(NewContents, ?any, Size);
  	Other ->
  