     {:::, [line: line], [{name, [line: line], []}, quote(do: term)]}
   end
 
-  def spec_to_ast(name, {:type, line, :bounded_fun, [{:type, _, :fun, [{:type, _, :product, args}, result]}, constraints]})
-      when is_atom(name) do
+  def spec_to_ast(name, {:type, line, :bounded_fun, [type, constrs]}) when is_atom(name) do
+    {:type, _, :fun, [{:type, _, :product, args}, result]} = type
+
     guards =
-      for {:type, _, :constraint, [{:atom, _, :is_subtype}, [{:var, _, var}, type]]} <- constraints do
+      for {:type, _, :constraint, [{:atom, _, :is_subtype}, [{:var, _, var}, type]]} <- constrs do
         {var, typespec_to_ast(type)}
       end
 
     meta = [line: line]
 
-    vars = args ++ [result]
-           |> Enum.flat_map(&collect_vars/1)
-           |> Enum.uniq
-           |> Kernel.--(Keyword.keys(guards))
-           |> Enum.map(&{&1, {:var, meta, nil}})
+    vars =
+      (args ++ [result])
+      |> Enum.flat_map(&collect_vars/1)
+      |> Enum.uniq()
+      |> Kernel.--(Keyword.keys(guards))
+      |> Enum.map(&{&1, {:var, meta, nil}})
 
     args = for arg <- args, do: typespec_to_ast(arg)
 
-    {:when, meta, [
+    when_args = [
       {:::, meta, [{name, [line: line], args}, typespec_to_ast(result)]},
       guards ++ vars
-    ]}
+    ]
+
+    {:when, meta, when_args}
   end
 
   @doc """
   Converts a type clause back to Elixir AST.
   """
   def type_to_ast(type)
+
   def type_to_ast({{:record, record}, fields, args}) when is_atom(record) do
     fields = for field <- fields, do: typespec_to_ast(field)
     args = for arg <- args, do: typespec_to_ast(arg)
     type = {:{}, [], [record | fields]}
-    quote do: unquote(record)(unquote_splicing(args)) :: unquote(type)
+    quote(do: unquote(record)(unquote_splicing(args)) :: unquote(type))
   end
 
   def type_to_ast({name, type, args}) when is_atom(name) do
     args = for arg <- args, do: typespec_to_ast(arg)
-    quote do: unquote(name)(unquote_splicing(args)) :: unquote(typespec_to_ast(type))
+    quote(do: unquote(name)(unquote_splicing(args)) :: unquote(typespec_to_ast(type)))
   end
 
   @doc false
   # TODO: Remove on v2.0
   def beam_typedocs(module) when is_atom(module) or is_binary(module) do
-    IO.write :stderr, "Kernel.Typespec.beam_typedocs/1 is deprecated, please use Code.get_docs/2 instead\n" <>
-                      Exception.format_stacktrace
+    warning =
+      "Kernel.Typespec.beam_typedocs/1 is deprecated, please use Code.get_docs/2 instead\n" <>
+        Exception.format_stacktrace()
+
+    IO.write(:stderr, warning)
+
     if docs = Code.get_docs(module, :type_docs) do
       for {tuple, _, _, doc} <- docs, do: {tuple, doc}
     end

    {line, doc} = get_doc_info(table, :typedoc, line)

    if kind == :typep && doc do
      :elixir_errors.warn(line, file, "type #{name}/#{arity} is private, " <>
                          "@typedoc's are always discarded for private types")
    end

    :ets.insert(table, {{:typedoc, {name, arity}}, line, kind, doc})

  ## Helpers

  @doc false
  def spec_to_signature({:when, _, [spec, _]}), do: type_to_signature(spec)
  def spec_to_signature(other), do: type_to_signature(other)

  @doc false
  def type_to_signature({:::, _, [{name, _, context}, _]}) when is_atom(name) and is_atom(context),
      do: {name, 0}

  def type_to_signature({:::, _, [{name, _, args}, _]}) when is_atom(name),
    do: {name, length(args)}

  def type_to_signature(_), do: :error

  ## Macro callbacks

