From 0a2d89212c7decbcc831d66fe8b84523f539af11 Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Thu, 9 Jul 2026 14:06:42 +0200 Subject: [PATCH] Tighten stdlib typespecs to match implementations Candidates found by cross-checking @specs against the type signatures inferred by the compiler (see #15559): these specs declared strictly wider return types than the functions can produce, where the gap carries no intentional API room (deliberately abstract contracts, such as atom() covering future values, are left untouched): * File.Stream.t/0: type the struct fields (mirrors IO.Stream.t/0) * Map.new/0: %{} instead of map() * Logger.levels/0: :logger.level() excludes :warn, which is only an accepted input alias and is never returned * Macro.Env.location/1 and Macro.Env.stacktrace/1: precise shapes Co-Authored-By: Claude Fable 5 --- lib/elixir/lib/file/stream.ex | 8 +++++++- lib/elixir/lib/macro/env.ex | 4 ++-- lib/elixir/lib/map.ex | 2 +- lib/elixir/lib/module.ex | 2 +- lib/logger/lib/logger.ex | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/elixir/lib/file/stream.ex b/lib/elixir/lib/file/stream.ex index 894055b9270..9e143f01e9b 100644 --- a/lib/elixir/lib/file/stream.ex +++ b/lib/elixir/lib/file/stream.ex @@ -18,7 +18,13 @@ defmodule File.Stream do defstruct path: nil, modes: [], line_or_bytes: :line, raw: true, node: nil - @type t :: %__MODULE__{} + @type t :: %__MODULE__{ + path: Path.t(), + modes: [term()], + line_or_bytes: :line | pos_integer(), + raw: boolean(), + node: node() + } @doc false def __build__(path, line_or_bytes, modes) do diff --git a/lib/elixir/lib/macro/env.ex b/lib/elixir/lib/macro/env.ex index 7b568b56d9b..f658c05523b 100644 --- a/lib/elixir/lib/macro/env.ex +++ b/lib/elixir/lib/macro/env.ex @@ -203,7 +203,7 @@ defmodule Macro.Env do Returns a keyword list containing the file and line information as keys. """ - @spec location(t) :: keyword + @spec location(t) :: [file: file, line: line] def location(env) def location(%{__struct__: Macro.Env, file: file, line: line}) do @@ -700,7 +700,7 @@ defmodule Macro.Env do @doc """ Returns the environment stacktrace. """ - @spec stacktrace(t) :: list + @spec stacktrace(t) :: [{module, atom, arity, keyword}] def stacktrace(%{__struct__: Macro.Env} = env) do cond do is_nil(env.module) -> diff --git a/lib/elixir/lib/map.ex b/lib/elixir/lib/map.ex index ee56679d64c..24e295027ab 100644 --- a/lib/elixir/lib/map.ex +++ b/lib/elixir/lib/map.ex @@ -201,7 +201,7 @@ defmodule Map do %{} """ - @spec new :: map + @spec new :: %{} def new, do: %{} @doc """ diff --git a/lib/elixir/lib/module.ex b/lib/elixir/lib/module.ex index e7c9f37d028..4d7c4aff34d 100644 --- a/lib/elixir/lib/module.ex +++ b/lib/elixir/lib/module.ex @@ -754,7 +754,7 @@ defmodule Module do """ @doc since: "1.12.0" - @spec reserved_attributes() :: map + @spec reserved_attributes() :: %{optional(atom()) => %{doc: binary()}} def reserved_attributes() do %{ after_compile: %{ diff --git a/lib/logger/lib/logger.ex b/lib/logger/lib/logger.ex index 96d61f31d7a..24127ca0890 100644 --- a/lib/logger/lib/logger.ex +++ b/lib/logger/lib/logger.ex @@ -501,7 +501,7 @@ defmodule Logger do """ @type level :: - :emergency | :alert | :critical | :error | :warning | :warn | :notice | :info | :debug + :emergency | :alert | :critical | :error | :warning | :notice | :info | :debug @type report :: map() | keyword() @type message :: :unicode.chardata() | String.Chars.t() | report() @type metadata :: keyword()